diff options
author | Roy Badami <roy@gnomon.org.uk> | 2014-07-07 22:06:21 +0100 |
---|---|---|
committer | Roy Badami <roy@gnomon.org.uk> | 2014-07-07 22:06:21 +0100 |
commit | 96df327834af3b55918adfac9b3f65adfc960b3a (patch) | |
tree | 8bd199df46ea6f39f7094c0e7db2185b4d3f5d6d | |
parent | 2e4fee2ac4824570c1340a8f8fe2aed4580de879 (diff) | |
parent | 1fedd65fcf9ac04b70f0fa8cf6caa9629857d586 (diff) |
Merge remote-tracking branch 'upstream/master'
Conflicts:
src/qt/overviewpage.cpp
src/qt/transactiondesc.cpp
331 files changed, 19555 insertions, 8425 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 @@ -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) @@ -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 6a8afe6e44..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 @@ -303,6 +304,8 @@ INCLUDES="$INCLUDES $PTHREAD_CFLAGS" # they also need to be passed down to any subprojects. Pull the results out of # the cache and add them to CPPFLAGS. AC_SYS_LARGEFILE +# detect POSIX or GNU variant of strerror_r +AC_FUNC_STRERROR_R if test x$ac_cv_sys_file_offset_bits != x && test x$ac_cv_sys_file_offset_bits != xno && @@ -366,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) @@ -664,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]) @@ -693,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/debian/manpages/bitcoin.conf.5 b/contrib/debian/manpages/bitcoin.conf.5 index eef213149d..7438b4b66a 100644 --- a/contrib/debian/manpages/bitcoin.conf.5 +++ b/contrib/debian/manpages/bitcoin.conf.5 @@ -37,9 +37,6 @@ You must set *rpcuser* to secure the JSON-RPC api. \fBrpcpassword=\fR\fI'password'\fR You must set *rpcpassword* to secure the JSON-RPC api. .TP -\fBrpctimeout=\fR\fI'30'\fR -How many seconds *bitcoin* will wait for a complete RPC HTTP request, after the HTTP connection is established. -.TP \fBrpcallowip=\fR\fI'192.168.1.*'\fR 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). .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 new file mode 100644 index 0000000000..bc3d561c35 --- /dev/null +++ b/contrib/gitian-descriptors/gitian-osx-bitcoin.yml @@ -0,0 +1,61 @@ +--- +name: "bitcoin" +suites: +- "precise" +architectures: +- "i386" +packages: +- "git-core" +- "automake" +- "faketime" +- "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-r3.tar.gz" +- "osx-depends-r4.tar.gz" +- "osx-depends-qt-5.2.1-r4.tar.gz" +- "MacOSX10.7.sdk.tar.gz" + +script: | + + HOST=x86_64-apple-darwin11 + PREFIX=`pwd`/osx-cross-depends/prefix + 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 -p osx-cross-depends/SDKs + + tar -C osx-cross-depends/SDKs -xf ${SOURCES_PATH}/MacOSX10.7.sdk.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 + + export ZERO_AR_DATE=1 + export QT_RCC_TEST=1 + ./autogen.sh + ./configure --host=${HOST} --with-boost=${PREFIX} CC=clang CXX=clang++ OBJC=clang OBJCXX=clang++ CFLAGS="-target ${HOST} -mmacosx-version-min=10.6 --sysroot ${SDK} -msse2 -Qunused-arguments" CXXFLAGS="-target ${HOST} -mmacosx-version-min=10.6 --sysroot ${SDK} -msse2 -Qunused-arguments" LDFLAGS="-B${NATIVEPREFIX}/bin -L${PREFIX}/lib -L${SDK}/usr/lib/i686-apple-darwin10/4.2.1" CPPFLAGS="-I${NATIVEPREFIX}/lib/clang/3.2/include -I${PREFIX}/include" SSL_LIBS="-lz -lssl -lcrypto" --disable-tests -with-gui=qt5 PKG_CONFIG_LIBDIR="${PREFIX}/lib/pkgconfig" --disable-dependency-tracking --disable-maintainer-mode + make dist + mkdir -p distsrc + cd distsrc + tar --strip-components=1 -xf ../bitcoin-*.tar* + ./configure --host=${HOST} --with-boost=${PREFIX} CC=clang CXX=clang++ OBJC=clang OBJCXX=clang++ CFLAGS="-target ${HOST} -mmacosx-version-min=10.6 --sysroot ${SDK} -msse2 -Qunused-arguments" CXXFLAGS="-target ${HOST} -mmacosx-version-min=10.6 --sysroot ${SDK} -msse2 -Qunused-arguments" LDFLAGS="-B${NATIVEPREFIX}/bin -L${PREFIX}/lib -L${SDK}/usr/lib/i686-apple-darwin10/4.2.1" CPPFLAGS="-I${NATIVEPREFIX}/lib/clang/3.2/include -I${PREFIX}/include" SSL_LIBS="-lz -lssl -lcrypto" --disable-tests -with-gui=qt5 PKG_CONFIG_LIBDIR="${PREFIX}/lib/pkgconfig" --disable-dependency-tracking --disable-maintainer-mode + make $MAKEOPTS + export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 + export FAKETIME=$REFERENCE_DATETIME + export TZ=UTC + make deploy + dmg dmg Bitcoin-Qt.dmg $OUTDIR/Bitcoin-Qt.dmg diff --git a/contrib/gitian-descriptors/gitian-osx-depends.yml b/contrib/gitian-descriptors/gitian-osx-depends.yml new file mode 100644 index 0000000000..07a021cf0c --- /dev/null +++ b/contrib/gitian-descriptors/gitian-osx-depends.yml @@ -0,0 +1,159 @@ +--- +name: "osx-depends" +suites: +- "precise" +architectures: +- "i386" +packages: +- "git-core" +- "automake" +- "p7zip-full" + +reference_datetime: "2013-06-01 00:00:00" +remotes: [] +files: +- "boost_1_55_0.tar.bz2" +- "db-4.8.30.NC.tar.gz" +- "miniupnpc-1.9.tar.gz" +- "openssl-1.0.1h.tar.gz" +- "protobuf-2.5.0.tar.bz2" +- "qrencode-3.4.3.tar.bz2" +- "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 "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 + + REVISION=r4 + export SOURCES_PATH=`pwd` + export TAR_OPTIONS="-m --mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" + export PATH=$HOME:$PATH + export SOURCES_PATH=`pwd` + export ZERO_AR_DATE=1 + + mkdir -p osx-cross-depends/build + cd osx-cross-depends + + PREFIX=`pwd`/prefix + NATIVEPREFIX=`pwd`/native-prefix + BUILD_BASE=`pwd`/build + SDK=`pwd`/SDKs/MacOSX10.7.sdk + HOST=x86_64-apple-darwin11 + MIN_VERSION=10.6 + + INT_CFLAGS="-target ${HOST} -mmacosx-version-min=${MIN_VERSION} --sysroot ${SDK} -msse2 -Qunused-arguments" + INT_CXXFLAGS="${INT_CFLAGS}" + INT_LDFLAGS="-L${PREFIX}/lib -L${SDK}/usr/lib/i686-apple-darwin10/4.2.1" + INT_LDFLAGS_CLANG="-B${NATIVEPREFIX}/bin" + INT_CPPFLAGS="-I${PREFIX}/include" + INT_CC=clang + INT_CXX=clang++ + INT_OBJC=clang + INT_OBJCXX=clang++ + INT_AR=${HOST}-ar + INT_RANLIB=${HOST}-ranlib + INT_LIBTOOL=${HOST}-libtool + INT_INSTALL_NAME_TOOL=${HOST}-install_name_tool + + export PATH=${NATIVEPREFIX}/bin:${PATH} + + mkdir -p ${NATIVEPREFIX}/bin + mkdir -p ${NATIVEPREFIX}/lib + mkdir -p ${PREFIX}/bin + mkdir -p ${PREFIX}/lib + mkdir -p ${BUILD_BASE} + + mkdir -p SDKs + tar -C SDKs -xf ${SOURCES_PATH}/MacOSX10.7.sdk.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 + BUILD_DIR=${BUILD_BASE}/db-4.8.30.NC + + tar -C ${BUILD_BASE} -xf ${SOURCE_FILE} + sed -i 's/__atomic_compare_exchange/__atomic_compare_exchange_db/g' ${BUILD_DIR}/dbinc/atomic.h + pushd ${BUILD_DIR} + cd build_unix; + ../dist/configure --host=${HOST} --prefix="${PREFIX}" --disable-shared --enable-cxx CC="${INT_CC}" CXX="${INT_CXX}" AR="${INT_AR}" RANLIB="${INT_RANLIB}" OBJC="${INT_OBJC}" OBJCXX="${INT_OBJCXX}" CFLAGS="${INT_CFLAGS}" CXXFLAGS="${INT_CXXFLAGS}" LDFLAGS="${INT_CLANG_LDFLAGS} ${INT_LDFLAGS}" CPPFLAGS="${INT_CPPFLAGS}" + make $MAKEOPTS libdb.a libdb_cxx.a + make install_lib install_include + popd + + # openssl + 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} + sed -ie "s|cc:|${INT_CC}:|" ${BUILD_DIR}/Configure + sed -ie "s|\(-arch [_a-zA-Z0-9]*\)|\1 --sysroot ${SDK} -target ${HOST} -msse2|" ${BUILD_DIR}/Configure + AR="${INT_AR}" RANLIB="${INT_RANLIB}" ./Configure --prefix=${PREFIX} --openssldir=${PREFIX}/etc/openssl zlib shared no-krb5 darwin64-x86_64-cc ${INT_LDFLAGS} ${INT_CLANG_LDFLAGS} ${INT_CPPFLAGS} + sed -i "s|engines apps test|engines|" ${BUILD_DIR}/Makefile + sed -i "/define DATE/d" ${BUILD_DIR}/crypto/Makefile + make -j1 build_libs libcrypto.pc libssl.pc openssl.pc + make -j1 install_sw + popd + + #libminiupnpc + SOURCE_FILE=${SOURCES_PATH}/miniupnpc-1.9.tar.gz + BUILD_DIR=${BUILD_BASE}/miniupnpc-1.9 + + tar -C ${BUILD_BASE} -xf ${SOURCE_FILE} + pushd ${BUILD_DIR} + CFLAGS="${INT_CFLAGS} ${INT_CPPFLAGS}" make $MAKEOPTS OS=Darwin CC="${INT_CC}" AR="${INT_AR}" libminiupnpc.a + install -d ${PREFIX}/include/miniupnpc + install *.h ${PREFIX}/include/miniupnpc + install libminiupnpc.a ${PREFIX}/lib + popd + + # qrencode + SOURCE_FILE=${SOURCES_PATH}/qrencode-3.4.3.tar.bz2 + BUILD_DIR=${BUILD_BASE}/qrencode-3.4.3 + tar -C ${BUILD_BASE} -xf ${SOURCE_FILE} + pushd ${BUILD_DIR} + + # m4 folder is not included in the stable release, which can confuse aclocal + # if its timestamp ends up being earlier than configure.ac when extracted + touch aclocal.m4 + ./configure --host=${HOST} --prefix="${PREFIX}" --disable-shared CC="${INT_CC}" CXX="${INT_CXX}" AR="${INT_AR}" RANLIB="${INT_RANLIB}" OBJC="${INT_OBJC}" OBJCXX="${INT_OBJCXX}" CFLAGS="${INT_CFLAGS}" CXXFLAGS="${INT_CXXFLAGS}" LDFLAGS="${INT_CLANG_LDFLAGS} ${INT_LDFLAGS}" CPPFLAGS="${INT_CPPFLAGS}" --disable-shared -without-tools --disable-sdltest --disable-dependency-tracking + make $MAKEOPTS + make install + popd + + # libprotobuf + SOURCE_FILE=${SOURCES_PATH}/protobuf-2.5.0.tar.bz2 + BUILD_DIR=${BUILD_BASE}/protobuf-2.5.0 + + tar -C ${BUILD_BASE} -xjf ${SOURCE_FILE} + pushd ${BUILD_DIR} + ./configure --host=${HOST} --prefix="${PREFIX}" --disable-shared --enable-cxx CC="${INT_CC}" CXX="${INT_CXX}" AR="${INT_AR}" RANLIB="${INT_RANLIB}" OBJC="${INT_OBJC}" OBJCXX="${INT_OBJCXX}" CFLAGS="${INT_CFLAGS}" CXXFLAGS="${INT_CXXFLAGS}" LDFLAGS="${INT_CLANG_LDFLAGS} ${INT_LDFLAGS}" CPPFLAGS="${INT_CPPFLAGS}" --enable-shared=no --disable-dependency-tracking --with-protoc=${NATIVEPREFIX}/bin/protoc + cd src + make $MAKEOPTS libprotobuf.la + make install-libLTLIBRARIES install-nobase_includeHEADERS + cd .. + make install-pkgconfigDATA + popd + + # boost + SOURCE_FILE=${SOURCES_PATH}/boost_1_55_0.tar.bz2 + BUILD_DIR=${BUILD_BASE}/boost_1_55_0 + + tar -C ${BUILD_BASE} -xf ${SOURCE_FILE} + pushd ${BUILD_DIR} + ./bootstrap.sh --with-libraries=chrono,filesystem,program_options,system,thread,test + echo "using darwin : : ${INT_CXX} : <cxxflags>\"${INT_CFLAGS} ${INT_CPPFLAGS}\" <linkflags>\"${INT_LDFLAGS} ${INT_CLANG_LDFLAGS}\" <archiver>\"${INT_LIBTOOL}\" <striper>\"${INT_STRIP}\" : ;" > "user-config.jam" + ./b2 -d2 --layout=tagged --build-type=complete --prefix="${PREFIX}" --toolset=darwin-4.2.1 --user-config=user-config.jam variant=release threading=multi link=static install + popd + + export GZIP="-9n" + find prefix | sort | tar --no-recursion -czf osx-depends-${REVISION}.tar.gz -T - + + mv osx-depends-${REVISION}.tar.gz $OUTDIR diff --git a/contrib/gitian-descriptors/gitian-osx-native.yml b/contrib/gitian-descriptors/gitian-osx-native.yml new file mode 100644 index 0000000000..a753ad704f --- /dev/null +++ b/contrib/gitian-descriptors/gitian-osx-native.yml @@ -0,0 +1,178 @@ +--- +name: "osx-native" +suites: +- "precise" +architectures: +- "i386" +packages: +- "git-core" +- "automake" +- "faketime" +- "libssl-dev" +- "libbz2-dev" +- "libz-dev" +- "cmake" +- "libcap-dev" +- "p7zip-full" +- "uuid-dev" + +reference_datetime: "2013-06-01 00:00:00" +remotes: [] +files: +- "10cc648683617cca8bcbeae507888099b41b530c.tar.gz" +- "cctools-809.tar.gz" +- "dyld-195.5.tar.gz" +- "ld64-127.2.tar.gz" +- "protobuf-2.5.0.tar.bz2" +- "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" +- "cdrkit-deterministic.patch" + + +script: | + + echo "18406961fd4a1ec5c7ea35c91d6a80a2f8bb797a2bd243a610bd75e13eff9aca 10cc648683617cca8bcbeae507888099b41b530c.tar.gz" | sha256sum -c + echo "03ba62749b843b131c7304a044a98c6ffacd65b1399b921d69add0375f79d8ad cctools-809.tar.gz" | sha256sum -c + 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 "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=r3 + export REFERENCE_DATETIME + export TAR_OPTIONS="-m --mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" + export FAKETIME=$REFERENCE_DATETIME + export TZ=UTC + + REAL_AR=`which ar` + REAL_RANLIB=`which ranlib` + REAL_DATE=`which date` + + echo '#!/bin/bash' > $HOME/ar + echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> $HOME/ar + echo "$REAL_AR \"\$@\"" >> $HOME/ar + + echo '#!/bin/bash' > $HOME/ranlib + echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> $HOME/ranlib + echo "$REAL_RANLIB \"\$@\"" >> $HOME/ranlib + + echo '#!/bin/bash' > $HOME/date + echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> $HOME/date + echo "$REAL_DATE \"\$@\"" >> $HOME/date + + chmod +x $HOME/ar $HOME/ranlib $HOME/date + + + export PATH=$HOME:$PATH + export SOURCES_PATH=`pwd` + + mkdir -p osx-cross-depends/build + cd osx-cross-depends + + NATIVEPREFIX=`pwd`/native-prefix + BUILD_BASE=`pwd`/build + SDK=`pwd`/SDKs/MacOSX10.7.sdk + HOST=x86_64-apple-darwin11 + MIN_VERSION=10.6 + + CFLAGS="" + CXXFLAGS="${CFLAGS}" + LDFLAGS="-L${NATIVEPREFIX}/lib" + + export PATH=${NATIVEPREFIX}/bin:${PATH} + + mkdir -p ${NATIVEPREFIX}/bin + mkdir -p ${NATIVEPREFIX}/lib + + 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 + BUILD_DIR=${BUILD_BASE}/clang+llvm-3.2-x86-linux-ubuntu-12.04 + + mkdir -p ${NATIVEPREFIX}/lib/clang/3.2/include + tar -C ${BUILD_BASE} -xf ${SOURCE_FILE} + cp ${BUILD_DIR}/bin/clang ${NATIVEPREFIX}/bin/ + cp ${BUILD_DIR}/bin/clang++ ${NATIVEPREFIX}/bin/ + cp ${BUILD_DIR}/lib/libLTO.so ${NATIVEPREFIX}/lib/ + cp ${BUILD_DIR}/lib/clang/3.2/include/* ${NATIVEPREFIX}/lib/clang/3.2/include + + # cctools + SOURCE_FILE=${SOURCES_PATH}/10cc648683617cca8bcbeae507888099b41b530c.tar.gz + BUILD_DIR=${BUILD_BASE}/toolchain4-10cc648683617cca8bcbeae507888099b41b530c + + tar -C ${BUILD_BASE} -xf ${SOURCE_FILE} + mkdir -p ${BUILD_DIR}/sdks + pushd ${BUILD_DIR}/sdks; + 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 + + tar -C ${BUILD_DIR} -xf ${SOURCES_PATH}/clang-llvm-3.2-x86-linux-ubuntu-12.04.tar.gz + # Hack in the use of our llvm headers rather than grabbing the old llvm-gcc. + sed -i "s|GCC_DIR|LLVM_CLANG_DIR|g" ${BUILD_DIR}/cctools2odcctools/extract.sh + sed -i "s|llvmgcc42-2336.1|clang+llvm-3.2-x86-linux-ubuntu-12.04|g" ${BUILD_DIR}/cctools2odcctools/extract.sh + sed -i "s|\${LLVM_CLANG_DIR}/llvmCore/include/llvm-c|\${LLVM_CLANG_DIR}/include/llvm-c \${LLVM_CLANG_DIR}/include/llvm |" ${BUILD_DIR}/cctools2odcctools/extract.sh + + sed -i "s|fAC_INIT|AC_INIT|" ${BUILD_DIR}/cctools2odcctools/files/configure.ac + 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.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} + + # The 'PC' define in sparc/reg.h conflicts but doesn't get used anyway. Just rename it. + sed -i "s|define\tPC|define\tPC_|" ${BUILD_DIR}/cctools2odcctools/odcctools-809/include/architecture/sparc/reg.h + make $MAKEOPTS + make install + popd + + # protoc + SOURCE_FILE=${SOURCES_PATH}/protobuf-2.5.0.tar.bz2 + BUILD_DIR=${BUILD_BASE}/protobuf-2.5.0 + + tar -C ${BUILD_BASE} -xjf ${SOURCE_FILE} + pushd ${BUILD_DIR}; + ./configure --enable-shared=no --disable-dependency-tracking --prefix=${NATIVEPREFIX} + make $MAKEOPTS + cp ${BUILD_DIR}/src/protoc ${NATIVEPREFIX}/bin/ + popd + + # cdrkit + SOURCE_FILE=${SOURCES_PATH}/cdrkit-1.1.11.tar.gz + BUILD_DIR=${BUILD_BASE}/cdrkit-1.1.11 + + tar -C ${BUILD_BASE} -xf ${SOURCE_FILE} + pushd ${BUILD_DIR} + patch -p1 < ${SOURCES_PATH}/cdrkit-deterministic.patch + cmake -DCMAKE_INSTALL_PREFIX=${NATIVEPREFIX} + make $MAKEOPTS genisoimage + make -C genisoimage install + popd + + # libdmg-hfsplus + SOURCE_FILE=${SOURCES_PATH}/libdmg-hfsplus-v0.1.tar.gz + BUILD_DIR=${BUILD_BASE}/libdmg-hfsplus-libdmg-hfsplus-v0.1 + + tar -C ${BUILD_BASE} -xf ${SOURCE_FILE} + mkdir -p ${BUILD_DIR}/build + pushd ${BUILD_DIR}/build + cmake -DCMAKE_INSTALL_PREFIX:PATH=${NATIVEPREFIX}/bin .. + make $MAKEOPTS + make install + popd + + rm -rf native-prefix/docs + + export GZIP="-9n" + find native-prefix | sort | tar --no-recursion -czf osx-native-depends-$REVISION.tar.gz -T - + mv osx-native-depends-$REVISION.tar.gz $OUTDIR diff --git a/contrib/gitian-descriptors/gitian-osx-qt.yml b/contrib/gitian-descriptors/gitian-osx-qt.yml new file mode 100644 index 0000000000..5e0ad9222a --- /dev/null +++ b/contrib/gitian-descriptors/gitian-osx-qt.yml @@ -0,0 +1,186 @@ +--- +name: "osx-qt" +suites: +- "precise" +architectures: +- "i386" +packages: +- "git-core" +- "automake" +- "p7zip-full" + +reference_datetime: "2013-06-01 00:00:00" +remotes: [] +files: +- "qt-everywhere-opensource-src-5.2.1.tar.gz" +- "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 + + REVISION=r4 + export SOURCES_PATH=`pwd` + export TAR_OPTIONS="-m --mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" + export ZERO_AR_DATE=1 + + export TZ=UTC + + REAL_DATE=`which date` + echo '#!/bin/bash' > $HOME/date + echo "$REAL_DATE -d \"${REFERENCE_DATETIME}\" \"\$@\"" >> $HOME/date + + chmod +x $HOME/date + export PATH=$HOME:$PATH + + mkdir -p osx-cross-depends/build + cd osx-cross-depends + + PREFIX=`pwd`/prefix + NATIVEPREFIX=`pwd`/native-prefix + BUILD_BASE=`pwd`/build + SDK=`pwd`/SDKs/MacOSX10.7.sdk + HOST=x86_64-apple-darwin11 + MIN_VERSION=10.6 + + INT_CFLAGS="-target ${HOST} -mmacosx-version-min=${MIN_VERSION} --sysroot ${SDK} -msse2 -Qunused-arguments" + INT_CXXFLAGS="${INT_CFLAGS}" + INT_LDFLAGS="-L${PREFIX}/lib -L${SDK}/usr/lib/i686-apple-darwin10/4.2.1" + INT_LDFLAGS_CLANG="-B${NATIVEPREFIX}/bin" + INT_CPPFLAGS="-I${PREFIX}/include" + INT_CC=clang + INT_CXX=clang++ + INT_OBJC=clang + INT_OBJCXX=clang++ + INT_AR=${HOST}-ar + INT_RANLIB=${HOST}-ranlib + INT_LIBTOOL=${HOST}-libtool + INT_INSTALL_NAME_TOOL=${HOST}-install_name_tool + + export PATH=${NATIVEPREFIX}/bin:${PATH} + + mkdir -p ${NATIVEPREFIX}/bin + mkdir -p ${NATIVEPREFIX}/lib + mkdir -p ${PREFIX}/bin + mkdir -p ${PREFIX}/lib + mkdir -p ${BUILD_BASE} + + mkdir -p SDKs + tar -C SDKs -xf ${SOURCES_PATH}/MacOSX10.7.sdk.tar.gz + + tar xf /home/ubuntu/build/osx-native-depends-r3.tar.gz + + export PATH=`pwd`/native-prefix/bin:$PATH + 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 + + + tar -C ${BUILD_BASE} -xf ${SOURCE_FILE} + + # Install our mkspec. All files are pulled from the macx-clang spec, except for + # our custom qmake.conf + SPECFILE=${BUILD_DIR}/qtbase/mkspecs/macx-clang-linux/qmake.conf + + mkdir -p ${BUILD_DIR}/qtbase/mkspecs/macx-clang-linux + cp -f ${BUILD_DIR}/qtbase/mkspecs/macx-clang/Info.plist.lib ${BUILD_DIR}/qtbase/mkspecs/macx-clang-linux/ + cp -f ${BUILD_DIR}/qtbase/mkspecs/macx-clang/Info.plist.app ${BUILD_DIR}/qtbase/mkspecs/macx-clang-linux/ + cp -f ${BUILD_DIR}/qtbase/mkspecs/macx-clang/qplatformdefs.h ${BUILD_DIR}/qtbase/mkspecs/macx-clang-linux/ + + cat > ${SPECFILE} <<ENDCONF + + MAKEFILE_GENERATOR = UNIX + CONFIG += app_bundle incremental global_init_link_order lib_version_first plugin_no_soname absolute_library_soname + QMAKE_INCREMENTAL_STYLE = sublib + + include(../common/macx.conf) + include(../common/gcc-base-mac.conf) + include(../common/clang.conf) + include(../common/clang-mac.conf) + + QMAKE_XCODE_VERSION=4.3 + QMAKE_XCODE_DEVELOPER_PATH=/Developer + + QMAKE_MACOSX_DEPLOYMENT_TARGET = ${MIN_VERSION} + + QMAKE_MAC_SDK=macosx + QMAKE_MAC_SDK.macosx.path = ${SDK} + QMAKE_MAC_SDK.macosx.platform_name = macosx + QMAKE_MAC_SDK_PATH=${SDK} + + QMAKE_CFLAGS += -target ${HOST} + QMAKE_OBJECTIVE_CFLAGS += -target ${HOST} + QMAKE_CXXFLAGS += -target ${HOST} + + QMAKE_LFLAGS += -target ${HOST} + QMAKE_AR = ${HOST}-ar cq + QMAKE_RANLIB=${HOST}-ranlib + QMAKE_LIBTOOL=${HOST}-libtool + QMAKE_INSTALL_NAME_TOOL=${HOST}-install_name_tool + + load(qt_config) + + ENDCONF + + pushd ${BUILD_DIR} + ./configure -release -opensource -openssl-linked \ + -no-audio-backend -no-javascript-jit -no-sql-sqlite -no-sql-tds \ + -no-cups -no-iconv -no-dbus -no-gif -no-audio-backend -no-freetype \ + -no-javascript-jit -no-sql-sqlite -no-nis -no-cups -no-iconv -no-pch \ + -no-dbus -no-gif -no-sm -nomake examples -no-feature-style-plastique \ + -no-xcb -no-qml-debug -no-pch -no-nis \ + -no-feature-style-cde -no-feature-style-s60 -no-feature-style-motif \ + -no-feature-style-windowsmobile -no-feature-style-windowsce \ + -no-feature-style-cleanlooks \ + -no-sql-db2 -no-sql-ibase -no-sql-oci -no-sql-tds -no-sql-mysql \ + -no-sql-odbc -no-sql-psql -no-sql-sqlite -no-sql-sqlite2 \ + -skip qtsvg -skip qtwebkit -skip qtwebkit-examples -skip qtserialport \ + -skip qtdeclarative -skip qtmultimedia -skip qtimageformats \ + -skip qtlocation -skip qtsensors -skip qtquick1 -skip qtxmlpatterns \ + -skip qtquickcontrols -skip qtactiveqt -skip qtconnectivity \ + -skip qtwinextras -skip qtscript \ + -prefix ${PREFIX} -bindir ${NATIVEPREFIX}/bin \ + -confirm-license -xplatform macx-clang-linux -v ${INT_LDFLAGS} + + # RCC's output is sorted using each file entry's hash as the key. Unfortunately, + # the hash function uses a random seed for each run so the results aren't + # deterministic. This leads to static resources being defined in a random order, + # which in-turn means that object files are not predictable. + # Fortunately, this upsets Qt's unit tests as well, so they've added the + # QT_RCC_TEST environment variable to set a pre-defined seed. Here, do the same + # thing for the same reason. + QT_RCC_TEST=1 make $MAKEOPTS module-qtbase-make_first + + + make $MAKEOPTS module-qttranslations-make_first + make $MAKEOPTS module-qttools-make_first + make $MAKEOPTS -C qtbase + make -C qtbase install + make -C qttranslations install + make -C qttools/src/linguist install + popd + + # This file should not be installed to the destination. It's native and + # non-deterministic. Remove it. + # See: https://bugreports.qt-project.org/browse/QTBUG-31393 + rm -f ${PREFIX}/lib/libQt5Bootstrap.a + + rm -f ${PREFIX}/lib/Qt*.framework/Qt*.prl + pushd ${PREFIX}/include + ln -sf ../lib/QtNetwork.framework/Headers/ QtNetwork + ln -sf ../lib/QtWidgets.framework/Headers/ QtWidgets + ln -sf ../lib/QtGui.framework/Headers/ QtGui + ln -sf ../lib/QtCore.framework/Headers/ QtCore + ln -sf ../lib/QtTest.framework/Headers/ QtTest + popd + + rm -f ${PREFIX}/lib/*.la + find ${PREFIX}/lib -name "*.prl" -delete + + export GZIP="-9n" + find native-prefix prefix | sort | tar --no-recursion -czf osx-depends-qt-5.2.1-${REVISION}.tar.gz -T - + + mv osx-depends-qt-5.2.1-${REVISION}.tar.gz $OUTDIR 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 5c310df1fc..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 @@ -580,7 +569,7 @@ try: except RuntimeError as e: if verbose >= 1: sys.stderr.write("Error: %s\n" % str(e)) - sys.exit(ret) + sys.exit(1) # ------------------------------------------------ @@ -593,7 +582,7 @@ if config.plugins: except RuntimeError as e: if verbose >= 1: sys.stderr.write("Error: %s\n" % str(e)) - sys.exit(ret) + sys.exit(1) # ------------------------------------------------ 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 new file mode 100644 index 0000000000..2be56c1592 --- /dev/null +++ b/doc/README_osx.txt @@ -0,0 +1,75 @@ +Deterministic OSX Dmg Notes. + +Working OSX DMG's are created in Linux by combining a recent clang, +the Apple's binutils (ld, ar, etc), and DMG authoring tools. + +Apple uses clang extensively for development and has upstreamed the necessary +functionality so that a vanilla clang can take advantage. It supports the use +of -F, -target, -mmacosx-version-min, and --sysroot, which are all necessary +when building for OSX. A pre-compiled version of 3.2 is used because it was not +available in the Precise repositories at the time this work was started. In the +future, it can be switched to use system packages instead. + +Apple's version of binutils (called cctools) contains lots of functionality +missing in the FSF's binutils. In addition to extra linker options for +frameworks and sysroots, several other tools are needed as well such as +install_name_tool, lipo, and nmedit. These do not build under linux, so they +have been patched to do so. The work here was used as a starting point: +https://github.com/mingwandroid/toolchain4 + +In order to build a working toolchain, the following source packages are needed +from Apple: cctools, dyld, and ld64. + +Beware. This part is ugly. Very very very ugly. In the future, this should be +broken out into a new repository and cleaned up. Additionally, the binaries +only work when built as x86 and not x86_64. This is an especially nasty +limitation because it must be linked with the toolchain's libLTO.so, meaning +that the entire toolchain must be x86. Gitian x86_64 should not be used until +this has been fixed, because it would mean that several native dependencies +(openssl, libuuid, etc) would need to be built as x86 first. + +These tools inject timestamps by default, which produce non-deterministic +binaries. The ZERO_AR_DATE environment variable is used to disable that. + +This version of cctools has been patched to use the current version of clang's +headers and and its libLTO.so rather than those from llvmgcc, as it was +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 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 +avoid including the SDK's files in Gitian's outputs. All interim tarballs are +fully deterministic and may be freely redistributed. + +genisoimage is used to create the initial DMG. It is not deterministic as-is, +so it has been patched. A system genisoimage will work fine, but it will not +be deterministic because the file-order will change between invocations. +The patch can be seen here: +https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff +No effort was made to fix this cleanly, so it likely leaks memory badly. But +it's only used for a single invocation, so that's no real concern. + +genisoimage cannot compress DMGs, so afterwards, the 'dmg' tool from the +libdmg-hfsplus project is used to compress it. There are several bugs in this +tool and its maintainer has seemingly abandoned the project. It has been forked +and is available (with fixes) here: https://github.com/theuni/libdmg-hfsplus . + +The 'dmg' tool has the ability to create DMG's from scratch as well, but this +functionality is broken. Only the compression feature is currently used. +Ideally, the creation could be fixed and genisoimage would no longer be necessary. + +Background images and other features can be added to DMG files by inserting a +.DS_Store before creation. The easiest way to create this file is to build a +DMG without one, move it to a device running OSX, customize the layout, then +grab the .DS_Store file for later use. That is the approach taken here. 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 b93c163748..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 @@ -34,21 +34,40 @@ Release Process popd pushd ./gitian-builder - Fetch and build inputs: (first time, or when dependency versions change) - +###fetch and build inputs: (first time, or when dependency versions change) + mkdir -p inputs; cd inputs/ + + 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' + wget 'http://www.opensource.apple.com/tarballs/cctools/cctools-809.tar.gz' + wget 'http://www.opensource.apple.com/tarballs/dyld/dyld-195.5.tar.gz' + 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 cd .. ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/boost-linux.yml mv build/out/boost-*.zip inputs/ @@ -64,28 +83,38 @@ Release Process mv build/out/qt-*.zip inputs/ ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/protobuf-win.yml mv build/out/protobuf-*.zip inputs/ + ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/gitian-osx-native.yml + mv build/out/osx-*.tar.gz inputs/ + ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/gitian-osx-depends.yml + mv build/out/osx-*.tar.gz inputs/ + ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/gitian-osx-qt.yml + mv build/out/osx-*.tar.gz inputs/ 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 ../../../ @@ -96,13 +125,19 @@ Release Process zip -r bitcoin-${VERSION}-win-gitian.zip * mv bitcoin-${VERSION}-win-gitian.zip ../../../ popd + ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-osx-bitcoin.yml + ./bin/gsign --signer $SIGNER --release ${VERSION}-osx --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx-bitcoin.yml + pushd build/out + mv Bitcoin-Qt.dmg ../../../ + popd popd Build output expected: 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. Gitian signatures (in gitian.sigs/${VERSION}[-win]/(your gitian key)/ + 3. OSX installer (Bitcoin-Qt.dmg) + 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 @@ -119,21 +154,6 @@ repackage gitian builds for release as stand-alone zip/tar/installer exe zip -r bitcoin-${VERSION}-win.zip bitcoin-${VERSION}-win rm -rf bitcoin-${VERSION}-win -**Perform Mac build:** - - OSX binaries are created by Gavin Andresen on a 64-bit, OSX 10.6 machine. - - ./autogen.sh - SDK=$(xcode-select --print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.6.sdk - CXXFLAGS="-mmacosx-version-min=10.6 -isysroot $SDK" ./configure --enable-upnp-default - make - export QTDIR=/opt/local/share/qt4 # needed to find translations/qt_*.qm files - T=$(contrib/qt_translations.py $QTDIR/translations src/qt/locale) - export CODESIGNARGS='--keychain ...path_to_keychain --sign "Developer ID Application: BITCOIN FOUNDATION, INC., THE"' - python2.7 contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -sign -add-qt-tr $T -dmg -fancy contrib/macdeploy/fancy.plist - - Build output expected: Bitcoin-Qt.dmg - ###Next steps: * Code-sign Windows -setup.exe (in a Windows virtual machine using signtool) @@ -157,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 @@ -167,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/netutil.py b/qa/rpc-tests/netutil.py new file mode 100644 index 0000000000..9bea2e355e --- /dev/null +++ b/qa/rpc-tests/netutil.py @@ -0,0 +1,134 @@ +# Linux network utilities +import sys +import socket +import fcntl +import struct +import array +import os +import binascii + +# Roughly based on http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/ by Ricardo Pascal +STATE_ESTABLISHED = '01' +STATE_SYN_SENT = '02' +STATE_SYN_RECV = '03' +STATE_FIN_WAIT1 = '04' +STATE_FIN_WAIT2 = '05' +STATE_TIME_WAIT = '06' +STATE_CLOSE = '07' +STATE_CLOSE_WAIT = '08' +STATE_LAST_ACK = '09' +STATE_LISTEN = '0A' +STATE_CLOSING = '0B' + +def get_socket_inodes(pid): + ''' + Get list of socket inodes for process pid. + ''' + base = '/proc/%i/fd' % pid + inodes = [] + for item in os.listdir(base): + target = os.readlink(os.path.join(base, item)) + if target.startswith('socket:'): + inodes.append(int(target[8:-1])) + return inodes + +def _remove_empty(array): + return [x for x in array if x !=''] + +def _convert_ip_port(array): + host,port = array.split(':') + # convert host from mangled-per-four-bytes form as used by kernel + host = binascii.unhexlify(host) + host_out = '' + for x in range(0, len(host)/4): + (val,) = struct.unpack('=I', host[x*4:(x+1)*4]) + host_out += '%08x' % val + + return host_out,int(port,16) + +def netstat(typ='tcp'): + ''' + Function to return a list with status of tcp connections at linux systems + To get pid of all network process running on system, you must run this script + as superuser + ''' + with open('/proc/net/'+typ,'r') as f: + content = f.readlines() + content.pop(0) + result = [] + for line in content: + line_array = _remove_empty(line.split(' ')) # Split lines and remove empty spaces. + tcp_id = line_array[0] + l_addr = _convert_ip_port(line_array[1]) + r_addr = _convert_ip_port(line_array[2]) + state = line_array[3] + inode = int(line_array[9]) # Need the inode to match with process pid. + nline = [tcp_id, l_addr, r_addr, state, inode] + result.append(nline) + return result + +def get_bind_addrs(pid): + ''' + Get bind addresses as (host,port) tuples for process pid. + ''' + inodes = get_socket_inodes(pid) + bind_addrs = [] + for conn in netstat('tcp') + netstat('tcp6'): + if conn[3] == STATE_LISTEN and conn[4] in inodes: + bind_addrs.append(conn[1]) + return bind_addrs + +# from: http://code.activestate.com/recipes/439093/ +def all_interfaces(): + ''' + Return all interfaces that are up + ''' + is_64bits = sys.maxsize > 2**32 + struct_size = 40 if is_64bits else 32 + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + max_possible = 8 # initial value + while True: + bytes = max_possible * struct_size + names = array.array('B', '\0' * bytes) + outbytes = struct.unpack('iL', fcntl.ioctl( + s.fileno(), + 0x8912, # SIOCGIFCONF + struct.pack('iL', bytes, names.buffer_info()[0]) + ))[0] + if outbytes == bytes: + max_possible *= 2 + else: + break + namestr = names.tostring() + return [(namestr[i:i+16].split('\0', 1)[0], + socket.inet_ntoa(namestr[i+20:i+24])) + for i in range(0, outbytes, struct_size)] + +def addr_to_hex(addr): + ''' + Convert string IPv4 or IPv6 address to binary address as returned by + get_bind_addrs. + Very naive implementation that certainly doesn't work for all IPv6 variants. + ''' + if '.' in addr: # IPv4 + addr = [int(x) for x in addr.split('.')] + elif ':' in addr: # IPv6 + sub = [[], []] # prefix, suffix + x = 0 + addr = addr.split(':') + for i,comp in enumerate(addr): + if comp == '': + if i == 0 or i == (len(addr)-1): # skip empty component at beginning or end + continue + x += 1 # :: skips to suffix + assert(x < 2) + else: # two bytes per component + val = int(comp, 16) + sub[x].append(val >> 8) + sub[x].append(val & 0xff) + nullbytes = 16 - len(sub[0]) - len(sub[1]) + assert((x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0)) + addr = sub[0] + ([0] * nullbytes) + sub[1] + else: + raise ValueError('Could not parse address %s' % addr) + return binascii.hexlify(bytearray(addr)) 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 new file mode 100755 index 0000000000..a823404e00 --- /dev/null +++ b/qa/rpc-tests/rpcbind_test.py @@ -0,0 +1,154 @@ +#!/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. + +# Test for -rpcbind, as well as -rpcallowip and -rpcconnect + +# 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 * +from netutil import * + +def run_bind_test(tmpdir, allow_ips, connect_to, addresses, expected): + ''' + Start a node with requested rpcallowip and rpcbind parameters, + then try to connect, and check if the set of bound addresses + matches the expected set. + ''' + expected = [(addr_to_hex(addr), port) for (addr, port) in expected] + base_args = ['-disablewallet', '-nolisten'] + if allow_ips: + base_args += ['-rpcallowip=' + x for x in allow_ips] + binds = ['-rpcbind='+addr for addr in addresses] + nodes = start_nodes(1, tmpdir, [base_args + binds], connect_to) + try: + pid = bitcoind_processes[0].pid + assert_equal(set(get_bind_addrs(pid)), set(expected)) + finally: + stop_nodes(nodes) + wait_bitcoinds() + +def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport): + ''' + Start a node with rpcwallow IP, and request getinfo + at a non-localhost IP. + ''' + base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips] + nodes = start_nodes(1, tmpdir, [base_args]) + try: + # connect to node through non-loopback interface + url = "http://rt:rt@%s:%d" % (rpchost, rpcport,) + node = AuthServiceProxy(url) + node.getinfo() + finally: + node = None # make sure connection will be garbage collected and closed + stop_nodes(nodes) + wait_bitcoinds() + + +def run_test(tmpdir): + assert(sys.platform == 'linux2') # due to OS-specific network stats queries, this test works only on Linux + # find the first non-loopback interface for testing + non_loopback_ip = None + for name,ip in all_interfaces(): + if ip != '127.0.0.1': + non_loopback_ip = ip + break + if non_loopback_ip is None: + 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', defaultport), ('::1', defaultport)]) + # check default with rpcallowip (IPv6 any) + run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', [], + [('::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', 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)]) + # check only IPv4 localhost (explicit) with multiple alternative ports on same host + run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171', '127.0.0.1:32172'], + [('127.0.0.1', 32171), ('127.0.0.1', 32172)]) + # check only IPv6 localhost (explicit) + run_bind_test(tmpdir, ['[::1]'], '[::1]', ['[::1]'], + [('::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', defaultport), ('::1', defaultport)]) + # check only non-loopback interface + run_bind_test(tmpdir, [non_loopback_ip], non_loopback_ip, [non_loopback_ip], + [(non_loopback_ip, defaultport)]) + + # Check that with invalid rpcallowip, we are denied + run_allowip_test(tmpdir, [non_loopback_ip], non_loopback_ip, defaultport) + try: + run_allowip_test(tmpdir, ['1.1.1.1'], non_loopback_ip, defaultport) + assert(not 'Connection not denied by rpcallowip as expected') + except ValueError: + pass + +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) + + run_test(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") + 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/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 1d0896a3fb..27c9f778f6 100644 --- a/qa/rpc-tests/util.py +++ b/qa/rpc-tests/util.py @@ -12,15 +12,19 @@ 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 +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""" @@ -57,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 @@ -68,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) @@ -86,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") @@ -111,23 +120,50 @@ 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''' + if rpchost is None: + return [] + + match = re.match('(\[[0-9a-fA-f:]+\]|[^:]+)(?::([0-9]+))?$', rpchost) + if not match: + raise ValueError('Invalid RPC host spec ' + rpchost) + + rpcconnect = match.group(1) + rpcport = match.group(2) + + if rpcconnect.startswith('['): # remove IPv6 [...] wrapping + rpcconnect = rpcconnect[1:-1] -def start_nodes(num_nodes, dir): - # Start bitcoinds, and wait for RPC interface to be up and running: + rv = ['-rpcconnect=' + rpcconnect] + if rpcport: + rv += ['-rpcport=' + rpcport] + return rv + +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 ] - bitcoind_processes.append(subprocess.Popen(args)) - subprocess.check_call([ "bitcoin-cli", "-datadir="+datadir, - "-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@127.0.0.1:%d"%(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") @@ -144,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/genbuild.sh b/share/genbuild.sh index 6890a6eba0..0800b31229 100755 --- a/share/genbuild.sh +++ b/share/genbuild.sh @@ -16,7 +16,7 @@ fi DESC="" SUFFIX="" LAST_COMMIT_DATE="" -if [ -e "$(which git)" -a -d ".git" ]; then +if [ -e "$(which git 2>/dev/null)" -a -d ".git" ]; then # clean 'dirty' status of touched files that haven't been modified git diff >/dev/null 2>/dev/null diff --git a/share/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 215d0319f9..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,17 +58,16 @@ 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 = \ addrman.h \ alert.h \ allocators.h \ - base58.h bignum.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 0b08ee3d06..c9e91beef1 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -2,11 +2,18 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "base58.h" + +#include "hash.h" +#include "uint256.h" + #include <assert.h> #include <stdint.h> #include <string.h> #include <vector> #include <string> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/static_visitor.hpp> /* All alphanumeric characters except for "0", "I", "O", and "l" */ static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; @@ -89,3 +96,180 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) str += pszBase58[*(it++)]; return str; } + +std::string EncodeBase58(const std::vector<unsigned char>& vch) { + return EncodeBase58(&vch[0], &vch[0] + vch.size()); +} + +bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet) { + return DecodeBase58(str.c_str(), vchRet); +} + +std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn) { + // add 4-byte hash check to the end + std::vector<unsigned char> vch(vchIn); + uint256 hash = Hash(vch.begin(), vch.end()); + vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4); + return EncodeBase58(vch); +} + +bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet) { + if (!DecodeBase58(psz, vchRet) || + (vchRet.size() < 4)) + { + vchRet.clear(); + return false; + } + // re-calculate the checksum, insure it matches the included 4-byte checksum + uint256 hash = Hash(vchRet.begin(), vchRet.end()-4); + if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) + { + vchRet.clear(); + return false; + } + vchRet.resize(vchRet.size()-4); + return true; +} + +bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet) { + return DecodeBase58Check(str.c_str(), vchRet); +} + +CBase58Data::CBase58Data() { + vchVersion.clear(); + vchData.clear(); +} + +void CBase58Data::SetData(const std::vector<unsigned char> &vchVersionIn, const void* pdata, size_t nSize) { + vchVersion = vchVersionIn; + vchData.resize(nSize); + if (!vchData.empty()) + memcpy(&vchData[0], pdata, nSize); +} + +void CBase58Data::SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend) { + SetData(vchVersionIn, (void*)pbegin, pend - pbegin); +} + +bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes) { + std::vector<unsigned char> vchTemp; + bool rc58 = DecodeBase58Check(psz, vchTemp); + if ((!rc58) || (vchTemp.size() < nVersionBytes)) { + vchData.clear(); + vchVersion.clear(); + return false; + } + vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes); + vchData.resize(vchTemp.size() - nVersionBytes); + if (!vchData.empty()) + memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size()); + OPENSSL_cleanse(&vchTemp[0], vchData.size()); + return true; +} + +bool CBase58Data::SetString(const std::string& str) { + return SetString(str.c_str()); +} + +std::string CBase58Data::ToString() const { + std::vector<unsigned char> vch = vchVersion; + vch.insert(vch.end(), vchData.begin(), vchData.end()); + return EncodeBase58Check(vch); +} + +int CBase58Data::CompareTo(const CBase58Data& b58) const { + if (vchVersion < b58.vchVersion) return -1; + if (vchVersion > b58.vchVersion) return 1; + if (vchData < b58.vchData) return -1; + if (vchData > b58.vchData) return 1; + return 0; +} + +namespace { + + class CBitcoinAddressVisitor : public boost::static_visitor<bool> { + private: + CBitcoinAddress *addr; + public: + CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { } + + bool operator()(const CKeyID &id) const { return addr->Set(id); } + 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); + return true; +} + +bool CBitcoinAddress::Set(const CScriptID &id) { + SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20); + return true; +} + +bool CBitcoinAddress::Set(const CTxDestination &dest) { + return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); +} + +bool CBitcoinAddress::IsValid() const { + bool fCorrectSize = vchData.size() == 20; + bool fKnownVersion = vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) || + vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); + return fCorrectSize && fKnownVersion; +} + +CTxDestination CBitcoinAddress::Get() const { + if (!IsValid()) + return CNoDestination(); + uint160 id; + memcpy(&id, &vchData[0], 20); + if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) + return CKeyID(id); + else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) + return CScriptID(id); + else + return CNoDestination(); +} + +bool CBitcoinAddress::GetKeyID(CKeyID &keyID) const { + if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) + return false; + uint160 id; + memcpy(&id, &vchData[0], 20); + keyID = CKeyID(id); + return true; +} + +bool CBitcoinAddress::IsScript() const { + return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); +} + +void CBitcoinSecret::SetKey(const CKey& vchSecret) { + assert(vchSecret.IsValid()); + SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size()); + if (vchSecret.IsCompressed()) + vchData.push_back(1); +} + +CKey CBitcoinSecret::GetKey() { + CKey ret; + ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1); + return ret; +} + +bool CBitcoinSecret::IsValid() const { + bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1); + bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY); + return fExpectedFormat && fCorrectVersion; +} + +bool CBitcoinSecret::SetString(const char* pszSecret) { + return CBase58Data::SetString(pszSecret) && IsValid(); +} + +bool CBitcoinSecret::SetString(const std::string& strSecret) { + return SetString(strSecret.c_str()); +} diff --git a/src/base58.h b/src/base58.h index 4fb436c5ed..70681f589a 100644 --- a/src/base58.h +++ b/src/base58.h @@ -15,17 +15,12 @@ #define BITCOIN_BASE58_H #include "chainparams.h" -#include "hash.h" #include "key.h" #include "script.h" -#include "uint256.h" #include <string> #include <vector> -#include <boost/variant/apply_visitor.hpp> -#include <boost/variant/static_visitor.hpp> - /** * Encode a byte sequence as a base58-encoded string. * pbegin and pend cannot be NULL, unless both are. @@ -35,10 +30,7 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) /** * Encode a byte vector as a base58-encoded string */ -inline std::string EncodeBase58(const std::vector<unsigned char>& vch) -{ - return EncodeBase58(&vch[0], &vch[0] + vch.size()); -} +std::string EncodeBase58(const std::vector<unsigned char>& vch); /** * Decode a base58-encoded string (psz) into a byte vector (vchRet). @@ -51,55 +43,24 @@ bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet); * Decode a base58-encoded string (str) into a byte vector (vchRet). * return true if decoding is successful. */ -inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet) -{ - return DecodeBase58(str.c_str(), vchRet); -} +bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet); /** * Encode a byte vector into a base58-encoded string, including checksum */ -inline std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn) -{ - // add 4-byte hash check to the end - std::vector<unsigned char> vch(vchIn); - uint256 hash = Hash(vch.begin(), vch.end()); - vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4); - return EncodeBase58(vch); -} +std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn); /** * Decode a base58-encoded string (psz) that includes a checksum into a byte * vector (vchRet), return true if decoding is successful */ -inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet) -{ - if (!DecodeBase58(psz, vchRet)) - return false; - if (vchRet.size() < 4) - { - vchRet.clear(); - return false; - } - // re-calculate the checksum, insure it matches the included 4-byte checksum - uint256 hash = Hash(vchRet.begin(), vchRet.end()-4); - if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) - { - vchRet.clear(); - return false; - } - vchRet.resize(vchRet.size()-4); - return true; -} +inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet); /** * Decode a base58-encoded string (str) that includes a checksum into a byte * vector (vchRet), return true if decoding is successful */ -inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet) -{ - return DecodeBase58Check(str.c_str(), vchRet); -} +inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet); /** * Base class for all base58-encoded data @@ -114,64 +75,15 @@ protected: typedef std::vector<unsigned char, zero_after_free_allocator<unsigned char> > vector_uchar; vector_uchar vchData; - CBase58Data() - { - vchVersion.clear(); - vchData.clear(); - } - - void SetData(const std::vector<unsigned char> &vchVersionIn, const void* pdata, size_t nSize) - { - vchVersion = vchVersionIn; - vchData.resize(nSize); - if (!vchData.empty()) - memcpy(&vchData[0], pdata, nSize); - } - - void SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend) - { - SetData(vchVersionIn, (void*)pbegin, pend - pbegin); - } + CBase58Data(); + void SetData(const std::vector<unsigned char> &vchVersionIn, const void* pdata, size_t nSize); + void SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend); public: - bool SetString(const char* psz, unsigned int nVersionBytes = 1) - { - std::vector<unsigned char> vchTemp; - DecodeBase58Check(psz, vchTemp); - if (vchTemp.size() < nVersionBytes) - { - vchData.clear(); - vchVersion.clear(); - return false; - } - vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes); - vchData.resize(vchTemp.size() - nVersionBytes); - if (!vchData.empty()) - memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size()); - OPENSSL_cleanse(&vchTemp[0], vchData.size()); - return true; - } - - bool SetString(const std::string& str) - { - return SetString(str.c_str()); - } - - std::string ToString() const - { - std::vector<unsigned char> vch = vchVersion; - vch.insert(vch.end(), vchData.begin(), vchData.end()); - return EncodeBase58Check(vch); - } - - int CompareTo(const CBase58Data& b58) const - { - if (vchVersion < b58.vchVersion) return -1; - if (vchVersion > b58.vchVersion) return 1; - if (vchData < b58.vchData) return -1; - if (vchData > b58.vchData) return 1; - return 0; - } + bool SetString(const char* psz, unsigned int nVersionBytes = 1); + bool SetString(const std::string& str); + std::string ToString() const; + int CompareTo(const CBase58Data& b58) const; bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; } bool operator<=(const CBase58Data& b58) const { return CompareTo(b58) <= 0; } @@ -186,140 +98,37 @@ public: * Script-hash-addresses have version 5 (or 196 testnet). * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. */ -class CBitcoinAddress; -class CBitcoinAddressVisitor : public boost::static_visitor<bool> -{ -private: - CBitcoinAddress *addr; +class CBitcoinAddress : public CBase58Data { public: - CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { } - bool operator()(const CKeyID &id) const; - bool operator()(const CScriptID &id) const; - bool operator()(const CNoDestination &no) const; + bool Set(const CKeyID &id); + bool Set(const CScriptID &id); + bool Set(const CTxDestination &dest); + bool IsValid() const; + + CBitcoinAddress() {} + CBitcoinAddress(const CTxDestination &dest) { Set(dest); } + CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); } + CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); } + + CTxDestination Get() const; + bool GetKeyID(CKeyID &keyID) const; + bool IsScript() const; }; -class CBitcoinAddress : public CBase58Data -{ -public: - bool Set(const CKeyID &id) { - SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20); - return true; - } - - bool Set(const CScriptID &id) { - SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20); - return true; - } - - bool Set(const CTxDestination &dest) - { - return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); - } - - bool IsValid() const - { - bool fCorrectSize = vchData.size() == 20; - bool fKnownVersion = vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) || - vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); - return fCorrectSize && fKnownVersion; - } - - CBitcoinAddress() - { - } - - CBitcoinAddress(const CTxDestination &dest) - { - Set(dest); - } - - CBitcoinAddress(const std::string& strAddress) - { - SetString(strAddress); - } - - CBitcoinAddress(const char* pszAddress) - { - SetString(pszAddress); - } - - CTxDestination Get() const { - if (!IsValid()) - return CNoDestination(); - uint160 id; - memcpy(&id, &vchData[0], 20); - if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) - return CKeyID(id); - else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) - return CScriptID(id); - else - return CNoDestination(); - } - - bool GetKeyID(CKeyID &keyID) const { - if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) - return false; - uint160 id; - memcpy(&id, &vchData[0], 20); - keyID = CKeyID(id); - return true; - } - - bool IsScript() const { - return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); - } -}; - -bool inline CBitcoinAddressVisitor::operator()(const CKeyID &id) const { return addr->Set(id); } -bool inline CBitcoinAddressVisitor::operator()(const CScriptID &id) const { return addr->Set(id); } -bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { return false; } - /** * A base58-encoded secret key */ class CBitcoinSecret : public CBase58Data { public: - void SetKey(const CKey& vchSecret) - { - assert(vchSecret.IsValid()); - SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size()); - if (vchSecret.IsCompressed()) - vchData.push_back(1); - } - - CKey GetKey() - { - CKey ret; - ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1); - return ret; - } - - bool IsValid() const - { - bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1); - bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY); - return fExpectedFormat && fCorrectVersion; - } - - bool SetString(const char* pszSecret) - { - return CBase58Data::SetString(pszSecret) && IsValid(); - } - - bool SetString(const std::string& strSecret) - { - return SetString(strSecret.c_str()); - } - - CBitcoinSecret(const CKey& vchSecret) - { - SetKey(vchSecret); - } - - CBitcoinSecret() - { - } + void SetKey(const CKey& vchSecret); + CKey GetKey(); + bool IsValid() const; + bool SetString(const char* pszSecret); + bool SetString(const std::string& strSecret); + + CBitcoinSecret(const CKey& vchSecret) { SetKey(vchSecret); } + CBitcoinSecret() {} }; template<typename K, int Size, CChainParams::Base58Type Type> class CBitcoinExtKeyBase : public CBase58Data diff --git a/src/bignum.h b/src/bignum.h deleted file mode 100644 index 0259338b31..0000000000 --- a/src/bignum.h +++ /dev/null @@ -1,595 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_BIGNUM_H -#define BITCOIN_BIGNUM_H - -#include "serialize.h" -#include "uint256.h" -#include "version.h" - -#include <stdexcept> -#include <stdint.h> -#include <vector> - -#include <openssl/bn.h> - -/** Errors thrown by the bignum class */ -class bignum_error : public std::runtime_error -{ -public: - explicit bignum_error(const std::string& str) : std::runtime_error(str) {} -}; - - -/** RAII encapsulated BN_CTX (OpenSSL bignum context) */ -class CAutoBN_CTX -{ -protected: - BN_CTX* pctx; - BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; } - -public: - CAutoBN_CTX() - { - pctx = BN_CTX_new(); - if (pctx == NULL) - throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); - } - - ~CAutoBN_CTX() - { - if (pctx != NULL) - BN_CTX_free(pctx); - } - - operator BN_CTX*() { return pctx; } - BN_CTX& operator*() { return *pctx; } - BN_CTX** operator&() { return &pctx; } - bool operator!() { return (pctx == NULL); } -}; - - -/** C++ wrapper for BIGNUM (OpenSSL bignum) */ -class CBigNum : public BIGNUM -{ -public: - CBigNum() - { - BN_init(this); - } - - CBigNum(const CBigNum& b) - { - BN_init(this); - if (!BN_copy(this, &b)) - { - BN_clear_free(this); - throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); - } - } - - CBigNum& operator=(const CBigNum& b) - { - if (!BN_copy(this, &b)) - throw bignum_error("CBigNum::operator= : BN_copy failed"); - return (*this); - } - - ~CBigNum() - { - BN_clear_free(this); - } - - //CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'. - CBigNum(signed char n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(short n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(int n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(long n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(long long n) { BN_init(this); setint64(n); } - CBigNum(unsigned char n) { BN_init(this); setulong(n); } - CBigNum(unsigned short n) { BN_init(this); setulong(n); } - CBigNum(unsigned int n) { BN_init(this); setulong(n); } - CBigNum(unsigned long n) { BN_init(this); setulong(n); } - CBigNum(unsigned long long n) { BN_init(this); setuint64(n); } - explicit CBigNum(uint256 n) { BN_init(this); setuint256(n); } - - explicit CBigNum(const std::vector<unsigned char>& vch) - { - BN_init(this); - setvch(vch); - } - - void setulong(unsigned long n) - { - if (!BN_set_word(this, n)) - throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed"); - } - - unsigned long getulong() const - { - return BN_get_word(this); - } - - unsigned int getuint() const - { - return BN_get_word(this); - } - - int getint() const - { - unsigned long n = BN_get_word(this); - if (!BN_is_negative(this)) - return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n); - else - return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n); - } - - void setint64(int64_t sn) - { - unsigned char pch[sizeof(sn) + 6]; - unsigned char* p = pch + 4; - bool fNegative; - uint64_t n; - - if (sn < (int64_t)0) - { - // Since the minimum signed integer cannot be represented as positive so long as its type is signed, - // and it's not well-defined what happens if you make it unsigned before negating it, - // we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate - n = -(sn + 1); - ++n; - fNegative = true; - } else { - n = sn; - fNegative = false; - } - - bool fLeadingZeroes = true; - for (int i = 0; i < 8; i++) - { - unsigned char c = (n >> 56) & 0xff; - n <<= 8; - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = (fNegative ? 0x80 : 0); - else if (fNegative) - c |= 0x80; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } - - void setuint64(uint64_t n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fLeadingZeroes = true; - for (int i = 0; i < 8; i++) - { - unsigned char c = (n >> 56) & 0xff; - n <<= 8; - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } - - void setuint256(uint256 n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fLeadingZeroes = true; - unsigned char* pbegin = (unsigned char*)&n; - unsigned char* psrc = pbegin + sizeof(n); - while (psrc != pbegin) - { - unsigned char c = *(--psrc); - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize >> 0) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } - - uint256 getuint256() const - { - unsigned int nSize = BN_bn2mpi(this, NULL); - if (nSize < 4) - return 0; - std::vector<unsigned char> vch(nSize); - BN_bn2mpi(this, &vch[0]); - if (vch.size() > 4) - vch[4] &= 0x7f; - uint256 n = 0; - for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) - ((unsigned char*)&n)[i] = vch[j]; - return n; - } - - void setvch(const std::vector<unsigned char>& vch) - { - std::vector<unsigned char> vch2(vch.size() + 4); - unsigned int nSize = vch.size(); - // BIGNUM's byte stream format expects 4 bytes of - // big endian size data info at the front - vch2[0] = (nSize >> 24) & 0xff; - vch2[1] = (nSize >> 16) & 0xff; - vch2[2] = (nSize >> 8) & 0xff; - vch2[3] = (nSize >> 0) & 0xff; - // swap data to big endian - reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); - BN_mpi2bn(&vch2[0], vch2.size(), this); - } - - std::vector<unsigned char> getvch() const - { - unsigned int nSize = BN_bn2mpi(this, NULL); - if (nSize <= 4) - return std::vector<unsigned char>(); - std::vector<unsigned char> vch(nSize); - BN_bn2mpi(this, &vch[0]); - vch.erase(vch.begin(), vch.begin() + 4); - reverse(vch.begin(), vch.end()); - return vch; - } - - // The "compact" format is a representation of a whole - // number N using an unsigned 32bit number similar to a - // floating point format. - // The most significant 8 bits are the unsigned exponent of base 256. - // This exponent can be thought of as "number of bytes of N". - // The lower 23 bits are the mantissa. - // Bit number 24 (0x800000) represents the sign of N. - // N = (-1^sign) * mantissa * 256^(exponent-3) - // - // Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). - // MPI uses the most significant bit of the first byte as sign. - // Thus 0x1234560000 is compact (0x05123456) - // and 0xc0de000000 is compact (0x0600c0de) - // (0x05c0de00) would be -0x40de000000 - // - // Bitcoin only uses this "compact" format for encoding difficulty - // 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. - CBigNum& SetCompact(unsigned int nCompact) - { - unsigned int nSize = nCompact >> 24; - bool fNegative =(nCompact & 0x00800000) != 0; - unsigned int nWord = nCompact & 0x007fffff; - if (nSize <= 3) - { - nWord >>= 8*(3-nSize); - BN_set_word(this, nWord); - } - else - { - BN_set_word(this, nWord); - BN_lshift(this, this, 8*(nSize-3)); - } - BN_set_negative(this, fNegative); - return *this; - } - - unsigned int GetCompact() const - { - unsigned int nSize = BN_num_bytes(this); - unsigned int nCompact = 0; - if (nSize <= 3) - nCompact = BN_get_word(this) << 8*(3-nSize); - else - { - CBigNum bn; - BN_rshift(&bn, this, 8*(nSize-3)); - nCompact = BN_get_word(&bn); - } - // 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++; - } - nCompact |= nSize << 24; - nCompact |= (BN_is_negative(this) ? 0x00800000 : 0); - return nCompact; - } - - void SetHex(const std::string& str) - { - // skip 0x - const char* psz = str.c_str(); - while (isspace(*psz)) - psz++; - bool fNegative = false; - if (*psz == '-') - { - fNegative = true; - psz++; - } - if (psz[0] == '0' && tolower(psz[1]) == 'x') - psz += 2; - while (isspace(*psz)) - psz++; - - // hex string to bignum - *this = 0; - int n; - while ((n = HexDigit(*psz)) != -1) - { - *this <<= 4; - *this += n; - ++psz; - } - if (fNegative) - *this = 0 - *this; - } - - std::string ToString(int nBase=10) const - { - CAutoBN_CTX pctx; - CBigNum bnBase = nBase; - CBigNum bn0 = 0; - std::string str; - CBigNum bn = *this; - BN_set_negative(&bn, false); - CBigNum dv; - CBigNum rem; - if (BN_cmp(&bn, &bn0) == 0) - return "0"; - while (BN_cmp(&bn, &bn0) > 0) - { - if (!BN_div(&dv, &rem, &bn, &bnBase, pctx)) - throw bignum_error("CBigNum::ToString() : BN_div failed"); - bn = dv; - unsigned int c = rem.getulong(); - str += "0123456789abcdef"[c]; - } - if (BN_is_negative(this)) - str += "-"; - reverse(str.begin(), str.end()); - return str; - } - - std::string GetHex() const - { - return ToString(16); - } - - unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const - { - return ::GetSerializeSize(getvch(), nType, nVersion); - } - - template<typename Stream> - void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const - { - ::Serialize(s, getvch(), nType, nVersion); - } - - template<typename Stream> - void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) - { - std::vector<unsigned char> vch; - ::Unserialize(s, vch, nType, nVersion); - setvch(vch); - } - - - bool operator!() const - { - return BN_is_zero(this); - } - - CBigNum& operator+=(const CBigNum& b) - { - if (!BN_add(this, this, &b)) - throw bignum_error("CBigNum::operator+= : BN_add failed"); - return *this; - } - - CBigNum& operator-=(const CBigNum& b) - { - *this = *this - b; - return *this; - } - - CBigNum& operator*=(const CBigNum& b) - { - CAutoBN_CTX pctx; - if (!BN_mul(this, this, &b, pctx)) - throw bignum_error("CBigNum::operator*= : BN_mul failed"); - return *this; - } - - CBigNum& operator/=(const CBigNum& b) - { - *this = *this / b; - return *this; - } - - CBigNum& operator%=(const CBigNum& b) - { - *this = *this % b; - return *this; - } - - CBigNum& operator<<=(unsigned int shift) - { - if (!BN_lshift(this, this, shift)) - throw bignum_error("CBigNum:operator<<= : BN_lshift failed"); - return *this; - } - - CBigNum& operator>>=(unsigned int shift) - { - // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number - // if built on ubuntu 9.04 or 9.10, probably depends on version of OpenSSL - CBigNum a = 1; - a <<= shift; - if (BN_cmp(&a, this) > 0) - { - *this = 0; - return *this; - } - - if (!BN_rshift(this, this, shift)) - throw bignum_error("CBigNum:operator>>= : BN_rshift failed"); - return *this; - } - - - CBigNum& operator++() - { - // prefix operator - if (!BN_add(this, this, BN_value_one())) - throw bignum_error("CBigNum::operator++ : BN_add failed"); - return *this; - } - - const CBigNum operator++(int) - { - // postfix operator - const CBigNum ret = *this; - ++(*this); - return ret; - } - - CBigNum& operator--() - { - // prefix operator - CBigNum r; - if (!BN_sub(&r, this, BN_value_one())) - throw bignum_error("CBigNum::operator-- : BN_sub failed"); - *this = r; - return *this; - } - - const CBigNum operator--(int) - { - // postfix operator - const CBigNum ret = *this; - --(*this); - return ret; - } - - - friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b); -}; - - - -inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) -{ - CBigNum r; - if (!BN_add(&r, &a, &b)) - throw bignum_error("CBigNum::operator+ : BN_add failed"); - return r; -} - -inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) -{ - CBigNum r; - if (!BN_sub(&r, &a, &b)) - throw bignum_error("CBigNum::operator- : BN_sub failed"); - return r; -} - -inline const CBigNum operator-(const CBigNum& a) -{ - CBigNum r(a); - BN_set_negative(&r, !BN_is_negative(&r)); - return r; -} - -inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) -{ - CAutoBN_CTX pctx; - CBigNum r; - if (!BN_mul(&r, &a, &b, pctx)) - throw bignum_error("CBigNum::operator* : BN_mul failed"); - return r; -} - -inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) -{ - CAutoBN_CTX pctx; - CBigNum r; - if (!BN_div(&r, NULL, &a, &b, pctx)) - throw bignum_error("CBigNum::operator/ : BN_div failed"); - return r; -} - -inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) -{ - CAutoBN_CTX pctx; - CBigNum r; - if (!BN_mod(&r, &a, &b, pctx)) - throw bignum_error("CBigNum::operator% : BN_div failed"); - return r; -} - -inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) -{ - CBigNum r; - if (!BN_lshift(&r, &a, shift)) - throw bignum_error("CBigNum:operator<< : BN_lshift failed"); - return r; -} - -inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) -{ - CBigNum r = a; - r >>= shift; - return r; -} - -inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); } -inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); } -inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); } -inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); } -inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); } -inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); } - -#endif 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 ca6950a162..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,22 +85,154 @@ 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(); + 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 17aa0c9d4b..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); @@ -172,15 +173,10 @@ bool AppInit(int argc, char* argv[]) int main(int argc, char* argv[]) { - bool fRet = false; + SetupEnvironment(); // Connect bitcoind signal handlers noui_connect(); - fRet = AppInit(argc, argv); - - if (fRet && fDaemon) - return 0; - - return (fRet ? 0 : 1); + return (AppInit(argc, argv) ? 0 : 1); } 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 b52774ee20..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 = CBigNum(~uint256(0) >> 32); + 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,10 +128,10 @@ 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 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); txNew.vout[0].nValue = 50 * COIN; txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; genesis.vtx.push_back(txNew); @@ -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; - bnProofOfWorkLimit = CBigNum(~uint256(0) >> 1); + 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 = ®TestParams; 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 542afeaf92..446256ba82 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -6,22 +6,18 @@ #ifndef BITCOIN_CHAIN_PARAMS_H #define BITCOIN_CHAIN_PARAMS_H -#include "bignum.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) {} }; /** @@ -34,14 +30,6 @@ struct CDNSSeedData { class CChainParams { public: - enum Network { - MAIN, - TESTNET, - REGTEST, - - MAX_NETWORK_TYPES - }; - enum Base58Type { PUBKEY_ADDRESS, SCRIPT_ADDRESS, @@ -54,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 CBigNum& ProofOfWorkLimit() const { return bnProofOfWorkLimit; } + 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; - CBigNum bnProofOfWorkLimit; + 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; }; /** @@ -89,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. @@ -97,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 = ®TestParams; + 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 cbdd24e806..47f3b2a015 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -72,38 +72,67 @@ 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 +{ + return nSatoshisPerK*nSize / 1000; +} + +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) { } + +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 fNewer = false; - unsigned int nLowest = std::numeric_limits<unsigned int>::max(); +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 @@ -140,7 +169,7 @@ double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSiz std::string CTransaction::ToString() const { std::string str; - str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%u)\n", + str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n", GetHash().ToString().substr(0,10), nVersion, vin.size(), @@ -269,7 +298,7 @@ uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMer void CBlock::print() const { - LogPrintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", + LogPrintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), 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 77c32d0b49..880ccaca1d 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" @@ -25,10 +26,12 @@ #endif #include <stdint.h> +#include <stdio.h> #ifndef WIN32 #include <signal.h> #endif +#include "compat/sanity.h" #include <boost/algorithm/string/predicate.hpp> #include <boost/filesystem.hpp> @@ -39,7 +42,6 @@ using namespace std; using namespace boost; #ifdef ENABLE_WALLET -std::string strWalletFile; CWallet* pwalletMain; #endif @@ -59,6 +61,8 @@ enum BindFlags { BF_REPORT_ERROR = (1U << 1) }; +static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; +CClientUIInterface uiInterface; ////////////////////////////////////////////////////////////////////////////// // @@ -113,7 +117,6 @@ void Shutdown() RenameThread("bitcoin-shutoff"); mempool.AddTransactionsUpdated(1); StopRPCThreads(); - ShutdownRPCMining(); #ifdef ENABLE_WALLET if (pwalletMain) bitdb.Flush(false); @@ -121,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 @@ -185,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"; @@ -195,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"; @@ -205,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"; @@ -227,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 @@ -242,14 +253,18 @@ 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"; + 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"; @@ -263,25 +278,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)) { @@ -296,6 +312,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"; @@ -303,10 +321,11 @@ std::string HelpMessage(HelpMessageMode hmm) strUsage += "\n" + _("RPC server options:") + "\n"; strUsage += " -server " + _("Accept command line and JSON-RPC commands") + "\n"; + strUsage += " -rpcbind=<addr> " + _("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)") + "\n"; strUsage += " -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n"; strUsage += " -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n"; strUsage += " -rpcport=<port> " + _("Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)") + "\n"; - strUsage += " -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified IP address") + "\n"; + 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"; @@ -318,6 +337,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() { @@ -381,6 +412,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. @@ -489,7 +542,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 @@ -513,9 +566,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 @@ -530,6 +590,8 @@ 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); #endif @@ -553,36 +615,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 @@ -610,6 +683,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; @@ -674,10 +748,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"]) { @@ -701,40 +771,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; @@ -855,7 +919,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; @@ -911,7 +975,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; @@ -927,17 +991,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; @@ -1032,6 +1105,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 @@ -1078,17 +1174,16 @@ bool AppInit2(boost::thread_group& threadGroup) RandAddSeedPerfmon(); //// debug print - LogPrintf("mapBlockIndex.size() = %"PRIszu"\n", mapBlockIndex.size()); + LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); LogPrintf("nBestHeight = %d\n", chainActive.Height()); #ifdef ENABLE_WALLET - LogPrintf("setKeyPool.size() = %"PRIszu"\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0); - LogPrintf("mapWallet.size() = %"PRIszu"\n", pwalletMain ? pwalletMain->mapWallet.size() : 0); - LogPrintf("mapAddressBook.size() = %"PRIszu"\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0); + LogPrintf("setKeyPool.size() = %u\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0); + LogPrintf("mapWallet.size() = %u\n", pwalletMain ? pwalletMain->mapWallet.size() : 0); + 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/json/json_spirit_reader_template.h b/src/json/json_spirit_reader_template.h index 4dec00e6c9..46f5892f62 100644 --- a/src/json/json_spirit_reader_template.h +++ b/src/json/json_spirit_reader_template.h @@ -33,8 +33,8 @@ namespace json_spirit { - const spirit_namespace::int_parser < boost::int64_t > int64_p = spirit_namespace::int_parser < boost::int64_t >(); - const spirit_namespace::uint_parser< boost::uint64_t > uint64_p = spirit_namespace::uint_parser< boost::uint64_t >(); + const spirit_namespace::int_parser < int64_t > int64_p = spirit_namespace::int_parser < int64_t >(); + const spirit_namespace::uint_parser< uint64_t > uint64_p = spirit_namespace::uint_parser< uint64_t >(); template< class Iter_type > bool is_eq( Iter_type first, Iter_type last, const char* c_str ) @@ -270,12 +270,12 @@ namespace json_spirit add_to_current( Value_type() ); } - void new_int( boost::int64_t i ) + void new_int( int64_t i ) { add_to_current( i ); } - void new_uint64( boost::uint64_t ui ) + void new_uint64( uint64_t ui ) { add_to_current( ui ); } @@ -425,8 +425,8 @@ namespace json_spirit typedef boost::function< void( Char_type ) > Char_action; typedef boost::function< void( Iter_type, Iter_type ) > Str_action; typedef boost::function< void( double ) > Real_action; - typedef boost::function< void( boost::int64_t ) > Int_action; - typedef boost::function< void( boost::uint64_t ) > Uint64_action; + typedef boost::function< void( int64_t ) > Int_action; + typedef boost::function< void( uint64_t ) > Uint64_action; Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) ); Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) ); diff --git a/src/json/json_spirit_value.h b/src/json/json_spirit_value.h index 7e83a2a7e3..13cc89210c 100644 --- a/src/json/json_spirit_value.h +++ b/src/json/json_spirit_value.h @@ -16,8 +16,8 @@ #include <cassert> #include <sstream> #include <stdexcept> +#include <stdint.h> #include <boost/config.hpp> -#include <boost/cstdint.hpp> #include <boost/shared_ptr.hpp> #include <boost/variant.hpp> @@ -45,8 +45,8 @@ namespace json_spirit Value_impl( const Array& value ); Value_impl( bool value ); Value_impl( int value ); - Value_impl( boost::int64_t value ); - Value_impl( boost::uint64_t value ); + Value_impl( int64_t value ); + Value_impl( uint64_t value ); Value_impl( double value ); Value_impl( const Value_impl& other ); @@ -65,8 +65,8 @@ namespace json_spirit const Array& get_array() const; bool get_bool() const; int get_int() const; - boost::int64_t get_int64() const; - boost::uint64_t get_uint64() const; + int64_t get_int64() const; + uint64_t get_uint64() const; double get_real() const; Object& get_obj(); @@ -83,7 +83,7 @@ namespace json_spirit typedef boost::variant< String_type, boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >, - bool, boost::int64_t, double > Variant; + bool, int64_t, double > Variant; Value_type type_; Variant v_; @@ -258,13 +258,13 @@ namespace json_spirit template< class Config > Value_impl< Config >::Value_impl( int value ) : type_( int_type ) - , v_( static_cast< boost::int64_t >( value ) ) + , v_( static_cast< int64_t >( value ) ) , is_uint64_( false ) { } template< class Config > - Value_impl< Config >::Value_impl( boost::int64_t value ) + Value_impl< Config >::Value_impl( int64_t value ) : type_( int_type ) , v_( value ) , is_uint64_( false ) @@ -272,9 +272,9 @@ namespace json_spirit } template< class Config > - Value_impl< Config >::Value_impl( boost::uint64_t value ) + Value_impl< Config >::Value_impl( uint64_t value ) : type_( int_type ) - , v_( static_cast< boost::int64_t >( value ) ) + , v_( static_cast< int64_t >( value ) ) , is_uint64_( true ) { } @@ -390,19 +390,19 @@ namespace json_spirit } template< class Config > - boost::int64_t Value_impl< Config >::get_int64() const + int64_t Value_impl< Config >::get_int64() const { check_type( int_type ); - return boost::get< boost::int64_t >( v_ ); + return boost::get< int64_t >( v_ ); } template< class Config > - boost::uint64_t Value_impl< Config >::get_uint64() const + uint64_t Value_impl< Config >::get_uint64() const { check_type( int_type ); - return static_cast< boost::uint64_t >( get_int64() ); + return static_cast< uint64_t >( get_int64() ); } template< class Config > @@ -481,13 +481,13 @@ namespace json_spirit } template< class Value > - boost::int64_t get_value( const Value& value, Type_to_type< boost::int64_t > ) + int64_t get_value( const Value& value, Type_to_type< int64_t > ) { return value.get_int64(); } template< class Value > - boost::uint64_t get_value( const Value& value, Type_to_type< boost::uint64_t > ) + uint64_t get_value( const Value& value, Type_to_type< uint64_t > ) { return value.get_uint64(); } diff --git a/src/key.cpp b/src/key.cpp index b57b7c506c..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,30 +353,61 @@ public: } }; -}; // end of anonymous namespace +#endif -bool CKey::Check(const unsigned char *vch) { - // Do not convert to OpenSSL's data structures for range-checking keys, - // it's easy enough to do directly. - static const unsigned char vchMax[32] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, - 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, - 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40 - }; - bool fIsZero = true; - for (int i=0; i<32 && fIsZero; i++) - if (vch[i] != 0) - fIsZero = false; - if (fIsZero) - return false; - for (int i=0; i<32; i++) { - if (vch[i] < vchMax[i]) - return true; - if (vch[i] > vchMax[i]) - return false; +int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len) { + while (c1len > c2len) { + if (*c1) + return 1; + c1++; + c1len--; } - return true; + while (c2len > c1len) { + if (*c2) + return -1; + c2++; + c2len--; + } + while (c1len > 0) { + if (*c1 > *c2) + return 1; + if (*c2 > *c1) + return -1; + c1++; + c2++; + c1len--; + } + return 0; +} + +// Order of secp256k1's generator minus 1. +const unsigned char vchMaxModOrder[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40 +}; + +// Half of the order of secp256k1's generator minus 1. +const unsigned char vchMaxModHalfOrder[32] = { + 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x5D,0x57,0x6E,0x73,0x57,0xA4,0x50,0x1D, + 0xDF,0xE9,0x2F,0x46,0x68,0x1B,0x20,0xA0 +}; + +const unsigned char vchZero[0] = {}; + +} // anon namespace + +bool CKey::Check(const unsigned char *vch) { + return CompareBigEndian(vch, 32, vchZero, 0) > 0 && + CompareBigEndian(vch, 32, vchMaxModOrder, 32) <= 0; +} + +bool CKey::CheckSignatureElement(const unsigned char *vch, int len, bool half) { + return CompareBigEndian(vch, len, vchZero, 0) > 0 && + CompareBigEndian(vch, len, half ? vchMaxModHalfOrder : vchMaxModOrder, 32) <= 0; } void CKey::MakeNewKey(bool fCompressedIn) { @@ -367,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; @@ -378,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; } @@ -495,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 { @@ -517,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; @@ -531,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; } @@ -547,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); @@ -616,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 +} + + @@ -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); @@ -269,6 +265,9 @@ public: // Load private key and check that public key matches. bool Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck); + + // Check whether an element of a signature (r or s) is valid. + static bool CheckSignatureElement(const unsigned char *vch, int len, bool half); }; struct CExtPubKey { @@ -307,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 46402ea25b..2a4c88d565 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -33,6 +33,9 @@ bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey) bool CBasicKeyStore::AddCScript(const CScript& redeemScript) { + if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) + return error("CBasicKeyStore::AddCScript() : redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE); + LOCK(cs_KeyStore); mapScripts[redeemScript.GetID()] = redeemScript; return true; @@ -56,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/leveldb/Makefile b/src/leveldb/Makefile index 344ff2972a..f8903b69e4 100644 --- a/src/leveldb/Makefile +++ b/src/leveldb/Makefile @@ -72,7 +72,7 @@ SHARED = $(SHARED1) else # Update db.h if you change these. SHARED_MAJOR = 1 -SHARED_MINOR = 15 +SHARED_MINOR = 17 SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) SHARED2 = $(SHARED1).$(SHARED_MAJOR) SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR) @@ -190,19 +190,20 @@ PLATFORMSROOT=/Applications/Xcode.app/Contents/Developer/Platforms SIMULATORROOT=$(PLATFORMSROOT)/iPhoneSimulator.platform/Developer DEVICEROOT=$(PLATFORMSROOT)/iPhoneOS.platform/Developer IOSVERSION=$(shell defaults read $(PLATFORMSROOT)/iPhoneOS.platform/version CFBundleShortVersionString) +IOSARCH=-arch armv6 -arch armv7 -arch armv7s -arch arm64 .cc.o: mkdir -p ios-x86/$(dir $@) - $(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@ + $(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -arch x86_64 -c $< -o ios-x86/$@ mkdir -p ios-arm/$(dir $@) - xcrun -sdk iphoneos $(CXX) $(CXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@ + xcrun -sdk iphoneos $(CXX) $(CXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk $(IOSARCH) -c $< -o ios-arm/$@ lipo ios-x86/$@ ios-arm/$@ -create -output $@ .c.o: mkdir -p ios-x86/$(dir $@) - $(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@ + $(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -arch x86_64 -c $< -o ios-x86/$@ mkdir -p ios-arm/$(dir $@) - xcrun -sdk iphoneos $(CC) $(CFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@ + xcrun -sdk iphoneos $(CC) $(CFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk $(IOSARCH) -c $< -o ios-arm/$@ lipo ios-x86/$@ ios-arm/$@ -create -output $@ else diff --git a/src/leveldb/db/filename.cc b/src/leveldb/db/filename.cc index 27d750697b..da32946d99 100644 --- a/src/leveldb/db/filename.cc +++ b/src/leveldb/db/filename.cc @@ -29,19 +29,14 @@ std::string LogFileName(const std::string& name, uint64_t number) { return MakeFileName(name, number, "log"); } -// TableFileName returns the filenames we usually write to, while -// SSTTableFileName returns the alternative filenames we also try to read from -// for backward compatibility. For now, swap them around. -// TODO: when compatibility is no longer necessary, swap them back -// (TableFileName to use "ldb" and SSTTableFileName to use "sst"). std::string TableFileName(const std::string& name, uint64_t number) { assert(number > 0); - return MakeFileName(name, number, "sst"); + return MakeFileName(name, number, "ldb"); } std::string SSTTableFileName(const std::string& name, uint64_t number) { assert(number > 0); - return MakeFileName(name, number, "ldb"); + return MakeFileName(name, number, "sst"); } std::string DescriptorFileName(const std::string& dbname, uint64_t number) { diff --git a/src/leveldb/db/log_reader.cc b/src/leveldb/db/log_reader.cc index b35f115aad..4919216d04 100644 --- a/src/leveldb/db/log_reader.cc +++ b/src/leveldb/db/log_reader.cc @@ -133,7 +133,9 @@ bool Reader::ReadRecord(Slice* record, std::string* scratch) { case kEof: if (in_fragmented_record) { - ReportCorruption(scratch->size(), "partial record without end(3)"); + // This can be caused by the writer dying immediately after + // writing a physical record but before completing the next; don't + // treat it as a corruption, just ignore the entire logical record. scratch->clear(); } return false; @@ -193,13 +195,12 @@ unsigned int Reader::ReadPhysicalRecord(Slice* result) { eof_ = true; } continue; - } else if (buffer_.size() == 0) { - // End of file - return kEof; } else { - size_t drop_size = buffer_.size(); + // Note that if buffer_ is non-empty, we have a truncated header at the + // end of the file, which can be caused by the writer crashing in the + // middle of writing the header. Instead of considering this an error, + // just report EOF. buffer_.clear(); - ReportCorruption(drop_size, "truncated record at end of file"); return kEof; } } @@ -213,8 +214,14 @@ unsigned int Reader::ReadPhysicalRecord(Slice* result) { if (kHeaderSize + length > buffer_.size()) { size_t drop_size = buffer_.size(); buffer_.clear(); - ReportCorruption(drop_size, "bad record length"); - return kBadRecord; + if (!eof_) { + ReportCorruption(drop_size, "bad record length"); + return kBadRecord; + } + // If the end of the file has been reached without reading |length| bytes + // of payload, assume the writer died in the middle of writing the record. + // Don't report a corruption. + return kEof; } if (type == kZeroType && length == 0) { diff --git a/src/leveldb/db/log_test.cc b/src/leveldb/db/log_test.cc index 4c5cf87573..91d3caafc3 100644 --- a/src/leveldb/db/log_test.cc +++ b/src/leveldb/db/log_test.cc @@ -351,20 +351,32 @@ TEST(LogTest, BadRecordType) { ASSERT_EQ("OK", MatchError("unknown record type")); } -TEST(LogTest, TruncatedTrailingRecord) { +TEST(LogTest, TruncatedTrailingRecordIsIgnored) { Write("foo"); ShrinkSize(4); // Drop all payload as well as a header byte ASSERT_EQ("EOF", Read()); - ASSERT_EQ(kHeaderSize - 1, DroppedBytes()); - ASSERT_EQ("OK", MatchError("truncated record at end of file")); + // Truncated last record is ignored, not treated as an error. + ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ("", ReportMessage()); } TEST(LogTest, BadLength) { + const int kPayloadSize = kBlockSize - kHeaderSize; + Write(BigString("bar", kPayloadSize)); + Write("foo"); + // Least significant size byte is stored in header[4]. + IncrementByte(4, 1); + ASSERT_EQ("foo", Read()); + ASSERT_EQ(kBlockSize, DroppedBytes()); + ASSERT_EQ("OK", MatchError("bad record length")); +} + +TEST(LogTest, BadLengthAtEndIsIgnored) { Write("foo"); ShrinkSize(1); ASSERT_EQ("EOF", Read()); - ASSERT_EQ(kHeaderSize + 2, DroppedBytes()); - ASSERT_EQ("OK", MatchError("bad record length")); + ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ("", ReportMessage()); } TEST(LogTest, ChecksumMismatch) { @@ -415,6 +427,24 @@ TEST(LogTest, UnexpectedFirstType) { ASSERT_EQ("OK", MatchError("partial record without end")); } +TEST(LogTest, MissingLastIsIgnored) { + Write(BigString("bar", kBlockSize)); + // Remove the LAST block, including header. + ShrinkSize(14); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ("", ReportMessage()); + ASSERT_EQ(0, DroppedBytes()); +} + +TEST(LogTest, PartialLastIsIgnored) { + Write(BigString("bar", kBlockSize)); + // Cause a bad record length in the LAST block. + ShrinkSize(1); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ("", ReportMessage()); + ASSERT_EQ(0, DroppedBytes()); +} + TEST(LogTest, ErrorJoinsRecords) { // Consider two fragmented records: // first(R1) last(R1) first(R2) last(R2) diff --git a/src/leveldb/db/repair.cc b/src/leveldb/db/repair.cc index 96c9b37af1..7727fafc58 100644 --- a/src/leveldb/db/repair.cc +++ b/src/leveldb/db/repair.cc @@ -242,7 +242,6 @@ class Repairer { } void ExtractMetaData() { - std::vector<TableInfo> kept; for (size_t i = 0; i < table_numbers_.size(); i++) { ScanTable(table_numbers_[i]); } diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc index 517edd3b18..aa83df55e4 100644 --- a/src/leveldb/db/version_set.cc +++ b/src/leveldb/db/version_set.cc @@ -54,20 +54,6 @@ static int64_t TotalFileSize(const std::vector<FileMetaData*>& files) { return sum; } -namespace { -std::string IntSetToString(const std::set<uint64_t>& s) { - std::string result = "{"; - for (std::set<uint64_t>::const_iterator it = s.begin(); - it != s.end(); - ++it) { - result += (result.size() > 1) ? "," : ""; - result += NumberToString(*it); - } - result += "}"; - return result; -} -} // namespace - Version::~Version() { assert(refs_ == 0); diff --git a/src/leveldb/include/leveldb/c.h b/src/leveldb/include/leveldb/c.h index 1fa58866c3..1048fe3b86 100644 --- a/src/leveldb/include/leveldb/c.h +++ b/src/leveldb/include/leveldb/c.h @@ -9,7 +9,6 @@ Does not support: . getters for the option types . custom comparators that implement key shortening - . capturing post-write-snapshot . custom iter, db, env, cache implementations using just the C bindings Some conventions: diff --git a/src/leveldb/include/leveldb/db.h b/src/leveldb/include/leveldb/db.h index 5ffb29d526..40851b2aa8 100644 --- a/src/leveldb/include/leveldb/db.h +++ b/src/leveldb/include/leveldb/db.h @@ -14,7 +14,7 @@ namespace leveldb { // Update Makefile if you change these static const int kMajorVersion = 1; -static const int kMinorVersion = 15; +static const int kMinorVersion = 17; struct Options; struct ReadOptions; diff --git a/src/leveldb/include/leveldb/slice.h b/src/leveldb/include/leveldb/slice.h index 74ea8fa49a..bc367986f7 100644 --- a/src/leveldb/include/leveldb/slice.h +++ b/src/leveldb/include/leveldb/slice.h @@ -94,7 +94,7 @@ inline bool operator!=(const Slice& x, const Slice& y) { } inline int Slice::compare(const Slice& b) const { - const int min_len = (size_ < b.size_) ? size_ : b.size_; + const size_t min_len = (size_ < b.size_) ? size_ : b.size_; int r = memcmp(data_, b.data_, min_len); if (r == 0) { if (size_ < b.size_) r = -1; 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 7b9ca2878c..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,12 +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); -static CMedianFilter<int> cPeerBlockCounts(8, 0); // Amount of blocks that other nodes claim to have +CTxMemPool mempool(::minRelayTxFee); struct COrphanBlock { uint256 hashBlock; @@ -74,6 +71,7 @@ const string strMessageMagic = "Bitcoin Signed Message:\n"; // Internal stuff namespace { + struct CBlockIndexWorkComparator { bool operator()(CBlockIndex *pa, CBlockIndex *pb) { @@ -122,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 @@ -132,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). @@ -146,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)); @@ -163,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() { @@ -175,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); } ////////////////////////////////////////////////////////////////////////////// @@ -205,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; @@ -215,6 +230,8 @@ struct CNodeState { CNodeState() { nMisbehavior = 0; fShouldBan = false; + pindexBestKnownBlock = NULL; + hashLastUnknownBlock = uint256(0); nBlocksToDownload = 0; nBlocksInFlight = 0; nLastBlockReceive = 0; @@ -276,7 +293,6 @@ void MarkBlockAsReceived(const uint256 &hash, NodeId nodeFrom = -1) { state->nLastBlockReceive = GetTimeMicros(); mapBlocksInFlight.erase(itInFlight); } - } // Requires cs_main. @@ -312,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; } @@ -373,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; } @@ -400,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; @@ -432,7 +491,7 @@ bool AddOrphanTx(const CTransaction& tx) BOOST_FOREACH(const CTxIn& txin, tx.vin) mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); - LogPrint("mempool", "stored orphan tx %s (mapsz %"PRIszu")\n", hash.ToString(), + LogPrint("mempool", "stored orphan tx %s (mapsz %u)\n", hash.ToString(), mapOrphanTransactions.size()); return true; } @@ -484,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,10 +574,14 @@ bool IsStandardTx(const CTransaction& tx, string& reason) BOOST_FOREACH(const CTxIn& txin, tx.vin) { - // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG - // pay-to-script-hash, which is 3 ~80-byte signatures, 3 - // ~65-byte public keys, plus a few script ops. - if (txin.scriptSig.size() > 500) { + // 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)+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 + // considered standard) + if (txin.scriptSig.size() > 1650) { reason = "scriptsig-size"; return false; } @@ -541,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; } @@ -575,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) { @@ -607,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; @@ -620,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) @@ -779,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) { @@ -792,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) @@ -831,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); @@ -842,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; } } } @@ -859,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); @@ -887,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()); @@ -908,54 +1028,54 @@ 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. - if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC)) + if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS)) { 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; } @@ -1003,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); } @@ -1158,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. @@ -1195,120 +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 CBigNum &bnLimit = Params().ProofOfWorkLimit(); - // Testnet has min-difficulty blocks - // after nTargetSpacing*2 time between blocks: - if (TestNet() && nTime > nTargetSpacing*2) - return bnLimit.GetCompact(); - - CBigNum 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 - CBigNum bnNew; - bnNew.SetCompact(pindexLast->nBits); - 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, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString()); - LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString()); - - return bnNew.GetCompact(); -} - -bool CheckProofOfWork(uint256 hash, unsigned int nBits) -{ - CBigNum bnTarget; - bnTarget.SetCompact(nBits); - - // Check range - if (bnTarget <= 0 || bnTarget > Params().ProofOfWorkLimit()) - return error("CheckProofOfWork() : nBits below minimum work"); - - // Check proof of work matches claimed amount - if (hash > bnTarget.getuint256()) - return error("CheckProofOfWork() : hash doesn't match nBits"); - - return true; -} - -// Return maximum amount of blocks that other nodes claim to have -int GetNumBlocksOfPeers() -{ - return std::max(cPeerBlockCounts.median(), Checkpoints::GetTotalBlocksEstimate()); -} - bool IsInitialBlockDownload() { LOCK(cs_main); @@ -1342,7 +1348,7 @@ void CheckForkWarningConditions() if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72) pindexBestForkTip = NULL; - if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (chainActive.Tip()->GetBlockWork() * 6).getuint256())) + if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (chainActive.Tip()->GetBlockWork() * 6))) { if (!fLargeWorkForkFound) { @@ -1398,7 +1404,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) // We define it this way because it allows us to only store the highest fork tip (+ base) which meets // the 7-block condition and from this always have the most-likely-to-cause-warning fork if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) && - pindexNewForkTip->nChainWork - pfork->nChainWork > (pfork->GetBlockWork() * 7).getuint256() && + pindexNewForkTip->nChainWork - pfork->nChainWork > (pfork->GetBlockWork() * 7) && chainActive.Height() - pindexNewForkTip->nHeight < 72) { pindexBestForkTip = pindexNewForkTip; @@ -1432,10 +1438,6 @@ void static InvalidChainFound(CBlockIndex* pindexNew) if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork) { pindexBestInvalid = pindexNew; - // The current code doesn't actually read the BestInvalidWork entry in - // the block database anymore, as it is derived from the flags in block - // index entry. We only write it for backward compatibility. - pblocktree->WriteBestInvalidWork(CBigNum(pindexBestInvalid->nChainWork)); uiInterface.NotifyBlocksChanged(); } LogPrintf("InvalidChainFound: invalid block=%s height=%d log2_work=%.8g date=%s\n", @@ -1472,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); } @@ -1486,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 @@ -1501,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); } @@ -1588,14 +1590,26 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach pvChecks->push_back(CScriptCheck()); check.swap(pvChecks->back()); } else if (!check()) { - if (flags & SCRIPT_VERIFY_STRICTENC) { - // For now, check whether the failure was caused by non-canonical - // encodings or not; if so, don't trigger DoS protection. - CScriptCheck check(coins, tx, i, flags & (~SCRIPT_VERIFY_STRICTENC), 0); + if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) { + // Check whether the failure was caused by a + // non-mandatory script verification check, such as + // non-standard DER encodings or non-null dummy + // arguments; if so, don't trigger DoS protection to + // avoid splitting the network between upgraded and + // non-upgraded nodes. + CScriptCheck check(coins, tx, i, + flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, 0); if (check()) - return state.Invalid(false, REJECT_NONSTANDARD, "non-canonical"); + return state.Invalid(false, REJECT_NONSTANDARD, "non-mandatory-script-verify-flag"); } - return state.DoS(100,false, REJECT_NONSTANDARD, "non-canonical"); + // Failures of other flags indicate a transaction that is + // invalid in new blocks, e.g. a invalid P2SH. We DoS ban + // such nodes as they are not following the protocol. That + // said during an upgrade careful thought should be taken + // as to the correct behavior - we may want to continue + // peering with non-upgraded nodes even after a soft-fork + // super-majority vote has passed. + return state.DoS(100,false, REJECT_INVALID, "mandatory-script-verify-flag-failed"); } } } @@ -1762,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"); @@ -1772,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); @@ -1824,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; @@ -1850,8 +1864,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C if (fJustCheck) return true; + // Correct transaction counts. + pindex->nTx = block.vtx.size(); + if (pindex->pprev) + pindex->nChainTx = pindex->pprev->nChainTx + block.vtx.size(); + // Write undo information to disk - if (pindex->GetUndoPos().IsNull() || (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) + if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) { if (pindex->GetUndoPos().IsNull()) { CDiskBlockPos pos; @@ -1865,7 +1884,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C pindex->nStatus |= BLOCK_HAVE_UNDO; } - pindex->nStatus = (pindex->nStatus & ~BLOCK_VALID_MASK) | BLOCK_VALID_SCRIPTS; + pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); CDiskBlockIndex blockindex(pindex); if (!pblocktree->WriteBlockIndex(blockindex)) @@ -1882,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; } @@ -1970,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); @@ -1981,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; } @@ -2014,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; } @@ -2059,10 +2073,11 @@ void static FindMostWorkChain() { CBlockIndex *pindexTest = pindexNew; bool fInvalidAncestor = false; while (pindexTest && !chainActive.Contains(pindexTest)) { - if (pindexTest->nStatus & BLOCK_FAILED_MASK) { + if (!pindexTest->IsValid(BLOCK_VALID_TRANSACTIONS) || !(pindexTest->nStatus & BLOCK_HAVE_DATA)) { // Candidate has an invalid ancestor, remove entire chain from the set. if (pindexBestInvalid == NULL || pindexNew->nChainWork > pindexBestInvalid->nChainWork) - pindexBestInvalid = pindexNew; CBlockIndex *pindexFailed = pindexNew; + pindexBestInvalid = pindexNew; + CBlockIndex *pindexFailed = pindexNew; while (pindexTest != pindexFailed) { pindexFailed->nStatus |= BLOCK_FAILED_CHILD; setBlockIndexValid.erase(pindexFailed); @@ -2073,75 +2088,118 @@ 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; } -bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos) +CBlockIndex* AddToBlockIndex(CBlockHeader& block) { // Check for duplicate uint256 hash = block.GetHash(); - if (mapBlockIndex.count(hash)) - return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString()), 0, "duplicate"); + std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hash); + if (it != mapBlockIndex.end()) + return it->second; // Construct new block index object CBlockIndex* pindexNew = new CBlockIndex(block); @@ -2157,43 +2215,46 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos { 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); + + 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) +{ pindexNew->nTx = block.vtx.size(); - pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256(); - pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx; + if (pindexNew->pprev) { + // Not the genesis block. + if (pindexNew->pprev->nChainTx) { + // This parent's block's total number transactions is known, so compute outs. + pindexNew->nChainTx = pindexNew->pprev->nChainTx + pindexNew->nTx; + } else { + // The total number of transactions isn't known yet. + // We will compute it when the block is connected. + pindexNew->nChainTx = 0; + } + } else { + // Genesis block. + pindexNew->nChainTx = pindexNew->nTx; + } pindexNew->nFile = pos.nFile; pindexNew->nDataPos = pos.nPos; pindexNew->nUndoPos = 0; - pindexNew->nStatus = BLOCK_VALID_TRANSACTIONS | BLOCK_HAVE_DATA; - setBlockIndexValid.insert(pindexNew); + pindexNew->nStatus |= BLOCK_HAVE_DATA; + + if (pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS)) + setBlockIndexValid.insert(pindexNew); 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; @@ -2288,27 +2349,34 @@ 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 + if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits)) + return state.DoS(50, error("CheckBlockHeader() : proof of work failed"), + REJECT_INVALID, "high-hash"); + + // Check timestamp + if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) + return state.Invalid(error("CheckBlockHeader() : block timestamp too far in the future"), + REJECT_INVALID, "time-too-new"); + + return true; +} bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot) { // These are checks that are independent of context // that can be verified before saving an orphan block. + if (!CheckBlockHeader(block, state, fCheckPOW)) + return false; + // Size limits if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return state.DoS(100, error("CheckBlock() : size limits failed"), REJECT_INVALID, "bad-blk-length"); - // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits)) - return state.DoS(50, error("CheckBlock() : proof of work failed"), - REJECT_INVALID, "high-hash"); - - // Check timestamp - if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) - return state.Invalid(error("CheckBlock() : block timestamp too far in the future"), - REJECT_INVALID, "time-too-new"); - // First transaction must be coinbase, the rest must not be if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) return state.DoS(100, error("CheckBlock() : first tx is not coinbase"), @@ -2323,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"), @@ -2348,20 +2411,47 @@ 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); return true; } -bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) +bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex) { AssertLockHeld(cs_main); // Check for duplicate uint256 hash = block.GetHash(); - if (mapBlockIndex.count(hash)) - return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex"), 0, "duplicate"); + std::map<uint256, CBlockIndex*>::iterator miSelf = mapBlockIndex.find(hash); + CBlockIndex *pindex = NULL; + if (miSelf != mapBlockIndex.end()) { + pindex = miSelf->second; + if (pindex->nStatus & BLOCK_FAILED_MASK) + 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; @@ -2383,12 +2473,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) return state.Invalid(error("AcceptBlock() : block's timestamp is too early"), REJECT_INVALID, "time-too-old"); - // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, block.vtx) - if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) - return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"), - REJECT_INVALID, "bad-txns-nonfinal"); - // Check that the block chain matches the known block chain up to a checkpoint if (!Checkpoints::CheckBlock(nHeight, hash)) return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight), @@ -2400,28 +2484,59 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) 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"); } - // 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 ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) || - (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 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())) - return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"), - REJECT_INVALID, "bad-cb-height"); - } + } + + if (pindex == NULL) + pindex = AddToBlockIndex(block); + + if (ppindex) + *ppindex = pindex; + + return true; +} + +bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp) +{ + AssertLockHeld(cs_main); + + CBlockIndex *&pindex = *ppindex; + + if (!AcceptBlockHeader(block, state, &pindex)) + return false; + + if (!CheckBlock(block, state)) { + if (state.Invalid() && !state.CorruptionPossible()) { + pindex->nStatus |= BLOCK_FAILED_VALID; + } + return false; + } + + int nHeight = pindex->nHeight; + + // Check that all transactions are finalized + BOOST_FOREACH(const CTransaction& tx, block.vtx) + if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) { + pindex->nStatus |= BLOCK_FAILED_VALID; + return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"), + REJECT_INVALID, "bad-txns-nonfinal"); + } + + // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height + // 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())) + { + 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"); } } @@ -2431,32 +2546,23 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) 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)) return state.Abort(_("Failed to write block")); - if (!AddToBlockIndex(block, state, blockPos)) - return error("AcceptBlock() : AddToBlockIndex failed"); + if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) + return error("AcceptBlock() : ReceivedBlockTransactions failed"); } catch(std::runtime_error &e) { 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++) { @@ -2467,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) @@ -2494,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)) @@ -2507,30 +2650,9 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl if (!CheckBlock(*pblock, state)) return error("ProcessBlock() : CheckBlock FAILED"); - CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); - if (pcheckpoint && pblock->hashPrevBlock != (chainActive.Tip() ? chainActive.Tip()->GetBlockHash() : uint256(0))) - { - // Extra checks to prevent "fill up memory by spamming with bogus blocks" - int64_t deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime; - if (deltaTime < 0) - { - return state.DoS(100, error("ProcessBlock() : block with timestamp before last checkpoint"), - REJECT_CHECKPOINT, "time-too-old"); - } - CBigNum bnNewBlock; - bnNewBlock.SetCompact(pblock->nBits); - CBigNum bnRequired; - bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); - if (bnNewBlock > bnRequired) - { - return state.DoS(100, error("ProcessBlock() : block with too little proof-of-work"), - REJECT_INVALID, "bad-diffbits"); - } - } - - - // If we don't already have its previous block, shunt it off to holding area until we get it - if (pblock->hashPrevBlock != 0 && !mapBlockIndex.count(pblock->hashPrevBlock)) + // If we don't already have its previous block (with full data), shunt it off to holding area until we get it + std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(pblock->hashPrevBlock); + if (pblock->hashPrevBlock != 0 && (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA))) { LogPrintf("ProcessBlock: ORPHAN BLOCK %lu, prev=%s\n", (unsigned long)mapOrphanBlocks.size(), pblock->hashPrevBlock.ToString()); @@ -2555,7 +2677,9 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl } // Store to disk - if (!AcceptBlock(*pblock, state, dbp)) + CBlockIndex *pindex = NULL; + bool ret = AcceptBlock(*pblock, state, &pindex, dbp); + if (!ret) return error("ProcessBlock() : AcceptBlock FAILED"); // Recursively process any orphan blocks that depended on this one @@ -2576,7 +2700,8 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl block.BuildMerkleTree(); // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned) CValidationState stateDummy; - if (AcceptBlock(block, stateDummy)) + CBlockIndex *pindexChild = NULL; + if (AcceptBlock(block, stateDummy, &pindexChild)) vWorkQueue.push_back(mi->second->hashBlock); mapOrphanBlocks.erase(mi->second->hashBlock); delete mi->second; @@ -2584,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; } @@ -2607,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)); @@ -2837,12 +2966,14 @@ bool static LoadBlockIndexDB() BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) { CBlockIndex* pindex = item.second; - pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + pindex->GetBlockWork().getuint256(); + pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + pindex->GetBlockWork(); pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx; - if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS && !(pindex->nStatus & BLOCK_FAILED_MASK)) + if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) 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 @@ -2851,6 +2982,24 @@ bool static LoadBlockIndexDB() if (pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile)) LogPrintf("LoadBlockIndexDB(): last block file info: %s\n", infoLastBlockFile.ToString()); + // Check presence of blk files + LogPrintf("Checking all blk files are present...\n"); + set<int> setBlkDataFiles; + BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) + { + CBlockIndex* pindex = item.second; + if (pindex->nStatus & BLOCK_HAVE_DATA) { + setBlkDataFiles.insert(pindex->nFile); + } + } + for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) + { + CDiskBlockPos pos(*it, 0); + if (!CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION)) { + return false; + } + } + // Check whether we need to continue reindexing bool fReindexing = false; pblocktree->ReadReindexing(fReindexing); @@ -2873,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) @@ -2894,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; @@ -2933,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)) @@ -2983,12 +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"); - if (!AddToBlockIndex(block, state, blockPos)) + 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()); } @@ -3045,7 +3209,7 @@ void PrintBlockTree() // print item CBlock block; ReadBlockFromDisk(block, pindex); - LogPrintf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"\n", + LogPrintf("%d (blk%05u.dat:0x%x) %s tx %u\n", pindex->nHeight, pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", block.GetBlockTime()), @@ -3118,7 +3282,6 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) // process block if (nBlockPos >= nStartByte) { - LOCK(cs_main); if (dbp) dbp->nPos = nBlockPos; CValidationState state; @@ -3282,7 +3445,8 @@ void static ProcessGetData(CNode* pfrom) { // Send block from disk CBlock block; - 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) @@ -3369,17 +3533,20 @@ 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 (%"PRIszu" 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"); return true; } - State(pfrom->GetId())->nLastBlockProcess = GetTimeMicros(); + { + LOCK(cs_main); + State(pfrom->GetId())->nLastBlockProcess = GetTimeMicros(); + } @@ -3401,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; @@ -3451,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()) @@ -3482,12 +3649,9 @@ 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); - - LOCK(cs_main); - cPeerBlockCounts.input(pfrom->nStartingHeight); } @@ -3516,7 +3680,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (vAddr.size() > 1000) { Misbehaving(pfrom->GetId(), 20); - return error("message addr size() = %"PRIszu"", vAddr.size()); + return error("message addr size() = %u", vAddr.size()); } // Store the new addresses @@ -3579,7 +3743,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (vInv.size() > MAX_INV_SZ) { Misbehaving(pfrom->GetId(), 20); - return error("message inv size() = %"PRIszu"", vInv.size()); + return error("message inv size() = %u", vInv.size()); } LOCK(cs_main); @@ -3592,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) { @@ -3605,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); } @@ -3618,14 +3785,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (vInv.size() > MAX_INV_SZ) { Misbehaving(pfrom->GetId(), 20); - return error("message getdata size() = %"PRIszu"", vInv.size()); + return error("message getdata size() = %u", vInv.size()); } if (fDebug || (vInv.size() != 1)) - LogPrint("net", "received getdata (%"PRIszu" 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); @@ -3647,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) @@ -3724,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 %"PRIszu")\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()); @@ -3754,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); @@ -3784,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); @@ -3800,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); + } + } + } @@ -3837,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) { @@ -3874,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; @@ -3915,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, %"PRIszu" 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, @@ -4034,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); } @@ -4050,7 +4230,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) bool ProcessMessages(CNode* pfrom) { //if (fDebug) - // LogPrintf("ProcessMessages(%"PRIszu" messages)\n", pfrom->vRecvMsg.size()); + // LogPrintf("ProcessMessages(%u messages)\n", pfrom->vRecvMsg.size()); // // Message format @@ -4078,7 +4258,7 @@ bool ProcessMessages(CNode* pfrom) CNetMessage& msg = *it; //if (fDebug) - // LogPrintf("ProcessMessages(message %u msgsz, %"PRIszu" bytes, complete:%s)\n", + // LogPrintf("ProcessMessages(message %u msgsz, %u bytes, complete:%s)\n", // msg.hdr.nMessageSize, msg.vRecv.size(), // msg.complete() ? "Y" : "N"); @@ -4124,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) @@ -4155,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; } @@ -4183,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) { @@ -4192,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"); } } @@ -4222,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()) @@ -4342,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) // @@ -4357,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().c_str(), state.name.c_str()); + LogPrint("net", "Requesting block %s peer=%d\n", hash.ToString(), pto->id); if (vGetData.size() >= 1000) { pto->PushMessage("getdata", vGetData); @@ -4374,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 825e577d1e..f6bac889be 100644 --- a/src/main.h +++ b/src/main.h @@ -7,10 +7,9 @@ #define BITCOIN_MAIN_H #if defined(HAVE_CONFIG_H) -#include "bitcoin-config.h" +#include "config/bitcoin-config.h" #endif -#include "bignum.h" #include "chainparams.h" #include "coins.h" #include "core.h" @@ -44,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) */ @@ -67,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; @@ -98,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; @@ -114,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 */ @@ -121,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); @@ -146,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 */ @@ -156,12 +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); -/** Get the number of active peers */ -int GetNumBlocksOfPeers(); /** 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 */ @@ -171,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); @@ -200,6 +189,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa struct CNodeStateStats { int nMisbehavior; + int nSyncHeight; }; struct CDiskBlockPos @@ -256,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 @@ -298,22 +281,15 @@ 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. bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCache &view, bool fScriptChecks = true, - unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, + unsigned int flags = STANDARD_SCRIPT_VERIFY_FLAGS, 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); @@ -477,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); }; @@ -603,11 +579,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos); // Context-independent validity checks +bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); // Store block on disk // if dbp is provided, the file is known to already reside on disk -bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp = NULL); +bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, CDiskBlockPos* dbp = NULL); +bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL); @@ -696,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; @@ -731,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; @@ -752,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; @@ -814,18 +791,19 @@ public: return (int64_t)nTime; } - CBigNum GetBlockWork() const + uint256 GetBlockWork() const { - CBigNum bnTarget; - bnTarget.SetCompact(nBits); - if (bnTarget <= 0) + uint256 bnTarget; + bool fNegative; + bool fOverflow; + bnTarget.SetCompact(nBits, &fNegative, &fOverflow); + if (fNegative || fOverflow || bnTarget == 0) return 0; - return (CBigNum(1)<<256) / (bnTarget+1); - } - - bool CheckIndex() const - { - return CheckProofOfWork(GetBlockHash(), nBits); + // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 + // as it's too large for a uint256. However, as 2**256 is at least as large + // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, + // or ~bnTarget / (nTarget+1) + 1. + return (~bnTarget / (bnTarget + 1)) + 1; } enum { nMedianTimeSpan=11 }; @@ -844,30 +822,57 @@ 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. + bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const + { + assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed. + if (nStatus & BLOCK_FAILED_MASK) + return false; + return ((nStatus & BLOCK_VALID_MASK) >= nUpTo); } -}; + // Raise the validity level of this block index entry. + // Returns true if the validity was changed. + bool RaiseValidity(enum BlockStatus nUpTo) + { + assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed. + if (nStatus & BLOCK_FAILED_MASK) + return false; + if ((nStatus & BLOCK_VALID_MASK) < nUpTo) { + nStatus = (nStatus & ~BLOCK_VALID_MASK) | nUpTo; + return true; + } + 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 @@ -925,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()); } }; @@ -999,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: @@ -1054,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; @@ -1110,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 3351908e65..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))) @@ -276,13 +258,15 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; + // Note that flags: we don't want to set mempool/IsStandard() + // policy here, but we still have to ensure that the block we + // create only contains transactions that are valid in new blocks. CValidationState state; - if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH)) + if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS)) 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); @@ -295,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 @@ -309,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); } } @@ -321,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 @@ -329,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); @@ -355,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 << CBigNum(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 ////////////////////////////////////////////////////////////////////////////// // @@ -417,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(); } @@ -463,7 +405,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { uint256 hash = pblock->GetHash(); - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + uint256 hashTarget = uint256().SetCompact(pblock->nBits); if (hash > hashTarget) return false; @@ -479,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; } @@ -508,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 %"PRIszu" 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 = CBigNum().SetCompact(pblock->nBits).getuint256(); - 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 = CBigNum().SetCompact(pblock->nBits).getuint256(); + // 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"); @@ -649,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(); } @@ -670,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 6bde1e7999..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; @@ -178,7 +187,7 @@ bool RecvLine(SOCKET hSocket, string& strLine) { // socket error int nErr = WSAGetLastError(); - LogPrint("net", "recv failed: %d\n", nErr); + LogPrint("net", "recv failed: %s\n", NetworkErrorString(nErr)); return false; } } @@ -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,16 +491,14 @@ 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; if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) - LogPrintf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError()); + LogPrintf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %s\n", NetworkErrorString(WSAGetLastError())); #else if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) - LogPrintf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno); + LogPrintf("ConnectSocket() : fcntl non-blocking setting failed, error %s\n", NetworkErrorString(errno)); #endif // Add node @@ -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; @@ -736,7 +746,7 @@ void SocketSendData(CNode *pnode) int nErr = WSAGetLastError(); if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) { - LogPrintf("socket send error %d\n", nErr); + LogPrintf("socket send error %s\n", NetworkErrorString(nErr)); pnode->CloseSocketDisconnect(); } } @@ -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) @@ -896,7 +905,7 @@ void ThreadSocketHandler() if (have_fds) { int nErr = WSAGetLastError(); - LogPrintf("socket select error %d\n", nErr); + LogPrintf("socket select error %s\n", NetworkErrorString(nErr)); for (unsigned int i = 0; i <= hSocketMax; i++) FD_SET(i, &fdsetRecv); } @@ -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: %d\n", 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 // @@ -1007,7 +1016,7 @@ void ThreadSocketHandler() if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) { if (!pnode->fDisconnect) - LogPrintf("socket recv error %d\n", nErr); + LogPrintf("socket recv error %s\n", NetworkErrorString(nErr)); pnode->CloseSocketDisconnect(); } } @@ -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; } @@ -1585,23 +1598,21 @@ bool BindListenPort(const CService &addrBind, string& strError) SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP); if (hListenSocket == INVALID_SOCKET) { - strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError()); + strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError())); LogPrintf("%s\n", 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) @@ -1609,7 +1620,7 @@ bool BindListenPort(const CService &addrBind, string& strError) if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) #endif { - strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError()); + strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %s)", NetworkErrorString(WSAGetLastError())); LogPrintf("%s\n", strError); return false; } @@ -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 } @@ -1638,7 +1647,7 @@ bool BindListenPort(const CService &addrBind, string& strError) if (nErr == WSAEADDRINUSE) strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin Core is probably already running."), addrBind.ToString()); else - strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString(), nErr, strerror(nErr)); + strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr)); LogPrintf("%s\n", strError); return false; } @@ -1647,7 +1656,7 @@ bool BindListenPort(const CService &addrBind, string& strError) // Listen for incoming connections if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) { - strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %d)"), WSAGetLastError()); + strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError())); LogPrintf("%s\n", strError); return false; } @@ -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 @@ -1785,7 +1791,7 @@ public: BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) if (hListenSocket != INVALID_SOCKET) if (closesocket(hListenSocket) == SOCKET_ERROR) - LogPrintf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); + LogPrintf("closesocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError())); // clean up some globals (to help leak detection) BOOST_FOREACH(CNode *pnode, vNodes) @@ -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); @@ -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 ec275f738c..175406322a 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; @@ -47,12 +58,10 @@ void SplitHostPort(std::string in, int &portOut, std::string &hostOut) { bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos); if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) { - char *endp = NULL; - int n = strtol(in.c_str() + colon + 1, &endp, 10); - if (endp && *endp == 0 && n >= 0) { + int32_t n; + if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) { in = in.substr(0, colon); - if (n > 0 && n < 0x10000) - portOut = n; + portOut = n; } } if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']') @@ -73,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; @@ -84,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; @@ -125,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) @@ -163,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); @@ -344,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; @@ -363,7 +370,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe } if (nRet == SOCKET_ERROR) { - LogPrintf("select() for %s failed: %i\n", addrConnect.ToString(), WSAGetLastError()); + LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); closesocket(hSocket); return false; } @@ -374,13 +381,13 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR) #endif { - LogPrintf("getsockopt() for %s failed: %i\n", addrConnect.ToString(), WSAGetLastError()); + LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); closesocket(hSocket); return false; } if (nRet != 0) { - LogPrintf("connect() to %s failed after select(): %s\n", addrConnect.ToString(), strerror(nRet)); + LogPrintf("connect() to %s failed after select(): %s\n", addrConnect.ToString(), NetworkErrorString(nRet)); closesocket(hSocket); return false; } @@ -391,7 +398,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe else #endif { - LogPrintf("connect() to %s failed: %i\n", addrConnect.ToString(), WSAGetLastError()); + LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); closesocket(hSocket); return false; } @@ -416,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; @@ -471,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; @@ -509,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; @@ -548,6 +533,22 @@ void CNetAddr::SetIP(const CNetAddr& ipIn) memcpy(ip, ipIn.ip, sizeof(ip)); } +void CNetAddr::SetRaw(Network network, const uint8_t *ip_in) +{ + switch(network) + { + case NET_IPV4: + memcpy(ip, pchIPv4, 12); + memcpy(ip+12, ip_in, 4); + break; + case NET_IPV6: + memcpy(ip, ip_in, 16); + break; + default: + assert(!"invalid network"); + } +} + static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43}; bool CNetAddr::SetSpecial(const std::string &strName) @@ -571,13 +572,12 @@ CNetAddr::CNetAddr() CNetAddr::CNetAddr(const struct in_addr& ipv4Addr) { - memcpy(ip, pchIPv4, 12); - memcpy(ip+12, &ipv4Addr, 4); + SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr); } CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr) { - memcpy(ip, &ipv6Addr, 16); + SetRaw(NET_IPV6, (const uint8_t*)&ipv6Addr); } CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup) @@ -1122,3 +1122,138 @@ void CService::SetPort(unsigned short portIn) { port = portIn; } + +CSubNet::CSubNet(): + valid(false) +{ + memset(netmask, 0, sizeof(netmask)); +} + +CSubNet::CSubNet(const std::string &strSubnet, bool fAllowLookup) +{ + size_t slash = strSubnet.find_last_of('/'); + std::vector<CNetAddr> vIP; + + valid = true; + // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address + memset(netmask, 255, sizeof(netmask)); + + std::string strAddress = strSubnet.substr(0, slash); + if (LookupHost(strAddress.c_str(), vIP, 1, fAllowLookup)) + { + network = vIP[0]; + if (slash != strSubnet.npos) + { + std::string strNetmask = strSubnet.substr(slash + 1); + int32_t n; + // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n + int noffset = network.IsIPv4() ? (12 * 8) : 0; + if (ParseInt32(strNetmask, &n)) // If valid number, assume /24 symtex + { + if(n >= 0 && n <= (128 - noffset)) // Only valid if in range of bits of address + { + n += noffset; + // Clear bits [n..127] + for (; n < 128; ++n) + netmask[n>>3] &= ~(1<<(n&7)); + } + else + { + valid = false; + } + } + else // If not a valid number, try full netmask syntax + { + if (LookupHost(strNetmask.c_str(), vIP, 1, false)) // Never allow lookup for netmask + { + // Remember: GetByte returns bytes in reversed order + // Copy only the *last* four bytes in case of IPv4, the rest of the mask should stay 1's as + // we don't want pchIPv4 to be part of the mask. + int asize = network.IsIPv4() ? 4 : 16; + for(int x=0; x<asize; ++x) + netmask[15-x] = vIP[0].GetByte(x); + } + else + { + valid = false; + } + } + } + } + else + { + valid = false; + } +} + +bool CSubNet::Match(const CNetAddr &addr) const +{ + if (!valid || !addr.IsValid()) + return false; + for(int x=0; x<16; ++x) + if ((addr.GetByte(x) & netmask[15-x]) != network.GetByte(x)) + return false; + return true; +} + +std::string CSubNet::ToString() const +{ + std::string strNetmask; + if (network.IsIPv4()) + strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], netmask[14], netmask[15]); + else + strNetmask = strprintf("%x:%x:%x:%x:%x:%x:%x:%x", + netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3], + netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7], + netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11], + netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]); + return network.ToString() + "/" + strNetmask; +} + +bool CSubNet::IsValid() const +{ + return valid; +} + +bool operator==(const CSubNet& a, const CSubNet& b) +{ + return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16); +} + +bool operator!=(const CSubNet& a, const CSubNet& b) +{ + return !(a==b); +} + +#ifdef WIN32 +std::string NetworkErrorString(int err) +{ + char buf[256]; + buf[0] = 0; + if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buf, sizeof(buf), NULL)) + { + return strprintf("%s (%d)", buf, err); + } + else + { + return strprintf("Unknown error (%d)", err); + } +} +#else +std::string NetworkErrorString(int err) +{ + char buf[256]; + const char *s = buf; + buf[0] = 0; + /* Too bad there are two incompatible implementations of the + * thread-safe strerror. */ +#ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */ + s = strerror_r(err, buf, sizeof(buf)); +#else /* POSIX variant always returns message in buffer */ + (void) strerror_r(err, buf, sizeof(buf)); +#endif + return strprintf("%s (%d)", s, err); +} +#endif diff --git a/src/netbase.h b/src/netbase.h index 95b1795767..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 { @@ -49,6 +47,13 @@ class CNetAddr explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false); void Init(); void SetIP(const CNetAddr& ip); + + /** + * Set raw IPv4 or IPv6 address (in network byte order) + * @note Only NET_IPV4 and NET_IPV6 are allowed for network. + */ + void SetRaw(Network network, const uint8_t *data); + bool SetSpecial(const std::string &strName); // for Tor addresses bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor) @@ -90,6 +95,29 @@ class CNetAddr ) }; +class CSubNet +{ + protected: + /// Network (base) address + CNetAddr network; + /// Netmask, in network byte order + uint8_t netmask[16]; + /// Is this value valid? (only used to signal parse errors) + bool valid; + + public: + CSubNet(); + explicit CSubNet(const std::string &strSubnet, bool fAllowLookup = false); + + bool Match(const CNetAddr &addr) const; + + std::string ToString() const; + bool IsValid() const; + + friend bool operator==(const CSubNet& a, const CSubNet& b); + friend bool operator!=(const CSubNet& a, const CSubNet& b); +}; + /** A combination of a network address (CNetAddr) and a (TCP) port */ class CService : public CNetAddr { @@ -133,21 +161,22 @@ 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); bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout); bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout); +/** Return readable error string for a network error code */ +std::string NetworkErrorString(int err); #endif 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 86e08ddcfa..1f23274299 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -10,14 +10,16 @@ #ifndef __INCLUDED_PROTOCOL_H__ #define __INCLUDED_PROTOCOL_H__ -#include "chainparams.h" #include "netbase.h" #include "serialize.h" #include "uint256.h" +#include "version.h" #include <stdint.h> #include <string> +#define MESSAGE_START_SIZE 4 + /** Message header. * (4) message start. * (12) command. @@ -62,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 8ec1ae2583..0000000000 --- a/src/qt/Makefile.am +++ /dev/null @@ -1,378 +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_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 31716ab825..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 @@ -459,6 +459,8 @@ WId BitcoinApplication::getMainWinId() const #ifndef BITCOIN_QT_TEST int main(int argc, char *argv[]) { + SetupEnvironment(); + /// 1. Parse command-line options. These take precedence over anything else. // Command-line options take precedence: ParseParameters(argc, argv); @@ -473,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 @@ -500,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; } @@ -543,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 75078581ce..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,76 +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="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 da7762282a..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) @@ -403,12 +406,15 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) setNumConnections(clientModel->getNumConnections()); connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); - setNumBlocks(clientModel->getNumBlocks(), clientModel->getNumBlocksOfPeers()); - connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int))); + setNumBlocks(clientModel->getNumBlocks()); + connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int))); // 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(); } @@ -617,7 +624,7 @@ void BitcoinGUI::setNumConnections(int count) labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count)); } -void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) +void BitcoinGUI::setNumBlocks(int count) { // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbelled text) statusBar()->clearMessage(); @@ -646,17 +653,10 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) QDateTime currentDate = QDateTime::currentDateTime(); int secs = lastBlockDate.secsTo(currentDate); - if(count < nTotalBlocks) - { - tooltip = tr("Processed %1 of %2 (estimated) blocks of transaction history.").arg(count).arg(nTotalBlocks); - } - else - { - tooltip = tr("Processed %1 blocks of transaction history.").arg(count); - } + tooltip = tr("Processed %1 blocks of transaction history.").arg(count); // Set icon state: spinning if catching up, tick otherwise - if(secs < 90*60 && count >= nTotalBlocks) + if(secs < 90*60) { tooltip = tr("Up to date") + QString(".<br>") + tooltip; labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); @@ -956,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); @@ -981,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 0cc1ebc502..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; @@ -130,7 +137,7 @@ public slots: /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set number of blocks shown in the UI */ - void setNumBlocks(int count, int nTotalBlocks); + void setNumBlocks(int count); /** Notify the user of an event from the core network or transaction handling code. @param[in] title the message box / notification title @@ -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 cf635e1941..089abd862c 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) @@ -188,6 +199,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 a3017b9a8b..f8c679711f 100644 --- a/src/qt/bitcoinunits.h +++ b/src/qt/bitcoinunits.h @@ -74,6 +74,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 @@ -93,6 +95,8 @@ public: static QString formatHtmlWithUnit(int unit, qint64 amount, bool plussign=false, SeparatorStyle separators=separatorStandard); //! 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 3c0564c208..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), - cachedNumBlocks(0), cachedNumBlocksOfPeers(0), + 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 @@ -101,19 +105,16 @@ void ClientModel::updateTimer() // Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change. // Periodically check and update with a timer. int newNumBlocks = getNumBlocks(); - int newNumBlocksOfPeers = getNumBlocksOfPeers(); // check for changed number of blocks we have, number of blocks peers claim to have, reindexing state and importing state - if (cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers || + if (cachedNumBlocks != newNumBlocks || cachedReindexing != fReindex || cachedImporting != fImporting) { cachedNumBlocks = newNumBlocks; - cachedNumBlocksOfPeers = newNumBlocksOfPeers; cachedReindexing = fReindex; cachedImporting = fImporting; - // ensure we return the maximum of newNumBlocksOfPeers and newNumBlocks to not create weird displays in the GUI - emit numBlocksChanged(newNumBlocks, std::max(newNumBlocksOfPeers, newNumBlocks)); + emit numBlocksChanged(newNumBlocks); } emit bytesChanged(getTotalBytesRecv(), getTotalBytesSent()); @@ -141,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(); @@ -166,11 +159,6 @@ enum BlockSource ClientModel::getBlockSource() const return BLOCK_SOURCE_NONE; } -int ClientModel::getNumBlocksOfPeers() const -{ - return GetNumBlocksOfPeers(); -} - QString ClientModel::getStatusBarWarnings() const { return QString::fromStdString(GetWarnings("statusbar")); @@ -181,6 +169,11 @@ OptionsModel *ClientModel::getOptionsModel() return optionsModel; } +PeerTableModel *ClientModel::getPeerTableModel() +{ + return peerTableModel; +} + QString ClientModel::formatFullVersion() const { return QString::fromStdString(FormatFullVersion()); @@ -207,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. @@ -231,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)); @@ -239,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 f29b695ea1..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,14 +56,10 @@ 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 enum BlockSource getBlockSource() const; - //! Return conservative estimate of total number of blocks, or 0 if unknown - int getNumBlocksOfPeers() const; //! Return warnings to be displayed in status bar QString getStatusBarWarnings() const; @@ -73,9 +71,9 @@ public: private: OptionsModel *optionsModel; + PeerTableModel *peerTableModel; int cachedNumBlocks; - int cachedNumBlocksOfPeers; bool cachedReindexing; bool cachedImporting; @@ -88,13 +86,16 @@ private: signals: void numConnectionsChanged(int count); - void numBlocksChanged(int count, int countOfPeers); + void numBlocksChanged(int count); void alertsChanged(const QString &warnings); void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut); //! 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..c73cf416a8 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,24 @@ 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" + return tr("lowest"); } // shows count of locked unspent outputs @@ -439,21 +442,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 +521,27 @@ 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); - - // Fee - int64_t nFee = nTransactionFee * (1 + (int64_t)nBytes / 1000); + sPriorityLabel = CoinControlDialog::getPriorityLabel(mempool, dPriority); // Min Fee - int64_t nMinFee = GetMinFee(txDummy, nBytes, AllowFree(dPriority), GMF_SEND); + nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool); + + double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget); + if (dPriorityNeeded <= 0) // 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 +572,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 +585,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(), payTxFee.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 +737,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 +770,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><b>Bitcoin Core</b> 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 &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 &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 31d61ec468..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,38 +256,15 @@ </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"> - <widget class="QLabel" name="numberOfBlocks"> - <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="11" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>Estimated total blocks</string> - </property> - </widget> - </item> <item row="11" column="1"> - <widget class="QLabel" name="totalBlocks"> + <widget class="QLabel" name="numberOfBlocks"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> </property> @@ -556,7 +559,7 @@ <item> <widget class="QLabel" name="label_16"> <property name="text"> - <string>In:</string> + <string>Received</string> </property> </widget> </item> @@ -636,7 +639,7 @@ <item> <widget class="QLabel" name="label_17"> <property name="text"> - <string>Out:</string> + <string>Sent</string> </property> </widget> </item> @@ -675,6 +678,281 @@ </item> </layout> </widget> + <widget class="QWidget" name="tab_peers"> + <attribute name="title"> + <string>&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_ach.ts b/src/qt/locale/bitcoin_ach.ts index cfe916093b..de5619bfc0 100644 --- a/src/qt/locale/bitcoin_ach.ts +++ b/src/qt/locale/bitcoin_ach.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ach" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ach" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_af_ZA.ts b/src/qt/locale/bitcoin_af_ZA.ts index a1f1abde69..6e8395e589 100644 --- a/src/qt/locale/bitcoin_af_ZA.ts +++ b/src/qt/locale/bitcoin_af_ZA.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="af_ZA" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="af_ZA" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> @@ -1890,7 +1898,7 @@ Address: %4 </message> <message> <source>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> - <translation>Die adres waarheen die betaling gestuur moet word (b.v. 1H7wyVL5HCNoVFyyBJSDojwyxcCChU7TPA)</translation> + <translation>Die adres waarheen die betaling gestuur moet word (b.v. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation> </message> <message> <source>Enter a label for this address to add it to your address book</source> diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts index daf09183c4..5877cc35d9 100644 --- a/src/qt/locale/bitcoin_ar.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ar" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ar" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -20,7 +20,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Copyright</source> - <translation type="unfinished"/> + <translation>الØقوق Ù…ØÙوظة</translation> </message> <message> <source>The Bitcoin Core developers</source> @@ -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> @@ -43,7 +43,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&New</source> - <translation type="unfinished"/> + <translation>&جديد</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> @@ -51,11 +51,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&Copy</source> - <translation type="unfinished"/> + <translation>&نسخ</translation> </message> <message> <source>C&lose</source> - <translation type="unfinished"/> + <translation>&اغلاق</translation> </message> <message> <source>&Copy Address</source> @@ -63,7 +63,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Delete the currently selected address from the list</source> - <translation type="unfinished"/> + <translation>Øذ٠العنوان المØدد من القائمة</translation> </message> <message> <source>Export the data in the current tab to a file</source> @@ -71,7 +71,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&Export</source> - <translation type="unfinished"/> + <translation>&تصدير</translation> </message> <message> <source>&Delete</source> @@ -79,23 +79,23 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Choose the address to send coins to</source> - <translation type="unfinished"/> + <translation>اختر العنوان الذي سترسل له العملات</translation> </message> <message> <source>Choose the address to receive coins with</source> - <translation type="unfinished"/> + <translation>اختر العنوان الذي تستقبل عليه العملات</translation> </message> <message> <source>C&hoose</source> - <translation type="unfinished"/> + <translation>&اختر</translation> </message> <message> <source>Sending addresses</source> - <translation type="unfinished"/> + <translation>ارسال العناوين</translation> </message> <message> <source>Receiving addresses</source> - <translation type="unfinished"/> + <translation>استقبال العناوين</translation> </message> <message> <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> @@ -107,7 +107,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Copy &Label</source> - <translation type="unfinished"/> + <translation>نسخ &الوصÙ</translation> </message> <message> <source>&Edit</source> @@ -115,7 +115,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Export Address List</source> - <translation type="unfinished"/> + <translation>تصدير قائمة العناوين</translation> </message> <message> <source>Comma separated file (*.csv)</source> @@ -123,7 +123,7 @@ 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> @@ -157,15 +157,15 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>New passphrase</source> - <translation>عبارة مرور جديدة</translation> + <translation>كلمة مرور جديدة</translation> </message> <message> <source>Repeat new passphrase</source> - <translation>ادخل الجملة السرية مرة أخرى</translation> + <translation>ادخل كلمة المرور الجديدة مرة أخرى</translation> </message> <message> <source>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>.</source> - <translation>أدخل عبارة مرور جديدة إلى المØÙظة. الرجاء استخدام عبارة مرور تتكون من10 Øرو٠عشوائية على الاقل, أو أكثر من 7 كلمات </translation> + <translation>أدخل كلمة مرور جديدة للمØÙظة. <br/>الرجاء استخدام كلمة مرور تتكون <b>من 10 Øرو٠عشوائية على الاقل</b>, أو <b>أكثر من 7 كلمات</b>. </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>هذه العملية تØتاج عبارة المرور Ù…ØÙظتك Ù„ÙتØها</translation> + <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>هذه العملية تØتاج عبارة المرور Ù…ØÙظتك ÙÙƒ تشÙيرها</translation> + <translation>هذه العملية تØتاج كلمة مرور Ù…ØÙظتك Ù„ÙÙƒ تشÙيرها </translation> </message> <message> <source>Decrypt wallet</source> @@ -189,15 +189,15 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Change passphrase</source> - <translation>تغيير عبارة المرور</translation> + <translation>تغيير كلمة المرور</translation> </message> <message> <source>Enter the old and new passphrase to the wallet.</source> - <translation>أدخل عبارة المرور القديمة والجديدة إلى المØÙظة.</translation> + <translation>أدخل كلمة المرور القديمة والجديدة للمØÙظة.</translation> </message> <message> <source>Confirm wallet encryption</source> - <translation>تأكيد التشÙير المØÙظة</translation> + <translation>تأكيد تشÙير المØÙظة</translation> </message> <message> <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> @@ -213,7 +213,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Warning: The Caps Lock key is on!</source> - <translation type="unfinished"/> + <translation>تØذير: Ù…ÙØªØ§Ø Ø§Ù„Øرو٠الكبيرة Ù…Ùعل</translation> </message> <message> <source>Wallet encrypted</source> @@ -229,12 +229,11 @@ 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>شل تشÙير المØÙظة بسبب خطأ داخلي. لم يتم تشÙير Ù…ØÙظتك.</translation> + <translation>Ùشل تشÙير المØÙظة بسبب خطأ داخلي. لم يتم تشÙير Ù…ØÙظتك.</translation> </message> <message> <source>The supplied passphrases do not match.</source> - <translation>عبارتي المرور ليستا متطابقتان -</translation> + <translation>كلمتي المرور ليستا متطابقتان</translation> </message> <message> <source>Wallet unlock failed</source> @@ -242,8 +241,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation>عبارة المرور التي تم إدخالها Ù„ÙÙƒ Ø´Ùرة المØÙظة غير صØÙŠØØ©. -</translation> + <translation>كلمة المرور التي تم إدخالها Ù„ÙÙƒ تشÙير المØÙظة غير صØÙŠØØ©.</translation> </message> <message> <source>Wallet decryption failed</source> @@ -262,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>مزامنة مع شبكة ...</translation> + <translation>مزامنة مع الشبكة ...</translation> </message> <message> <source>&Overview</source> - <translation>نظرة عامة</translation> + <translation>&نظرة عامة</translation> </message> <message> <source>Node</source> @@ -278,11 +276,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&Transactions</source> - <translation>المعاملات</translation> + <translation>&المعاملات</translation> </message> <message> <source>Browse transaction history</source> - <translation>تصÙØ Ø§Ù„ØªØ§Ø±ÙŠØ® المعاملات</translation> + <translation>تصÙØ Ø³Ø¬Ù„ المعاملات</translation> </message> <message> <source>E&xit</source> @@ -294,7 +292,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Show information about Bitcoin</source> - <translation> إظهار المزيد معلومات Øول Bitcoin</translation> + <translation> إظهار معلومات Øول بت كوين</translation> </message> <message> <source>About &Qt</source> @@ -306,19 +304,19 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&Options...</source> - <translation>خيارات ...</translation> + <translation>&خيارات ...</translation> </message> <message> <source>&Encrypt Wallet...</source> - <translation type="unfinished"/> + <translation>&تشÙير المØÙظة</translation> </message> <message> <source>&Backup Wallet...</source> - <translation type="unfinished"/> + <translation>&نسخ اØتياط للمØÙظة</translation> </message> <message> <source>&Change Passphrase...</source> - <translation type="unfinished"/> + <translation>&تغيير كلمة المرور</translation> </message> <message> <source>&Sending addresses...</source> @@ -330,7 +328,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Open &URI...</source> - <translation type="unfinished"/> + <translation>اÙØªØ &URI...</translation> </message> <message> <source>Importing blocks from disk...</source> @@ -354,11 +352,11 @@ 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>تغيير عبارة المرور المستخدمة لتشÙير المØÙظة</translation> + <translation>تغيير كلمة المرور المستخدمة لتشÙير المØÙظة</translation> </message> <message> <source>&Debug window</source> - <translation type="unfinished"/> + <translation>&ناÙذة المعالجة</translation> </message> <message> <source>Open debugging and diagnostic console</source> @@ -366,7 +364,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&Verify message...</source> - <translation type="unfinished"/> + <translation>&التØقق من الرسالة...</translation> </message> <message> <source>Bitcoin</source> @@ -378,19 +376,19 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&Send</source> - <translation type="unfinished"/> + <translation>%ارسل</translation> </message> <message> <source>&Receive</source> - <translation type="unfinished"/> + <translation>&استقبل</translation> </message> <message> <source>&Show / Hide</source> - <translation type="unfinished"/> + <translation>&عرض / اخÙاء</translation> </message> <message> <source>Show or hide the main Window</source> - <translation type="unfinished"/> + <translation>عرض او اخÙاء الناÙذة الرئيسية</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> @@ -406,15 +404,15 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&File</source> - <translation>ملÙ</translation> + <translation>&ملÙ</translation> </message> <message> <source>&Settings</source> - <translation>الاعدادات</translation> + <translation>&الاعدادات</translation> </message> <message> <source>&Help</source> - <translation>مساعدة</translation> + <translation>&مساعدة</translation> </message> <message> <source>Tabs toolbar</source> @@ -458,7 +456,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Bitcoin client</source> - <translation>عميل بتكوين</translation> + <translation>عميل بت كوين</translation> </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network</source> @@ -478,15 +476,15 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message numerus="yes"> <source>%n hour(s)</source> - <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation> + <translation><numerusform>%n ساعة</numerusform><numerusform>%n ساعة</numerusform><numerusform>%n ساعة</numerusform><numerusform>%n ساعات</numerusform><numerusform>%n ساعات</numerusform><numerusform>%n ساعات</numerusform></translation> </message> <message numerus="yes"> <source>%n day(s)</source> - <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation> + <translation><numerusform>%n يوم</numerusform><numerusform>%n يوم</numerusform><numerusform>%n يوم</numerusform><numerusform>%n أيام</numerusform><numerusform>%n أيام</numerusform><numerusform>%n ايام</numerusform></translation> </message> <message numerus="yes"> <source>%n week(s)</source> - <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation> + <translation><numerusform>%n اسبوع</numerusform><numerusform>%n اسبوع</numerusform><numerusform>%n اسبوع</numerusform><numerusform>%n اسابيع</numerusform><numerusform>%n اسابيع</numerusform><numerusform>%n اسابيع</numerusform></translation> </message> <message> <source>%1 and %2</source> @@ -514,15 +512,15 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Warning</source> - <translation type="unfinished"/> + <translation>تØذير</translation> </message> <message> <source>Information</source> - <translation type="unfinished"/> + <translation>معلومات</translation> </message> <message> <source>Up to date</source> - <translation>Ù…Øين</translation> + <translation>Ù…Øدث</translation> </message> <message> <source>Catching up...</source> @@ -534,7 +532,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Incoming transaction</source> - <translation>المعاملات واردة</translation> + <translation>المعاملات الواردة</translation> </message> <message> <source>Date: %1 @@ -542,15 +540,19 @@ Amount: %2 Type: %3 Address: %4 </source> - <translation type="unfinished"/> + <translation>التاريخ : 1% +القيمة: 2% +النوع: 3% +العنوان: 4% +</translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation>المØÙظة مشÙرة Ùˆ Ù…ÙتوØØ© Øاليا</translation> + <translation>المØÙظة <b>مشÙرة</b> Ùˆ <b>Ù…ÙتوØØ©</b> Øاليا</translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation>المØÙظة مشÙرة Ùˆ مقÙلة Øاليا</translation> + <translation>المØÙظة <b>مشÙرة</b> Ùˆ <b>مقÙلة</b> Øاليا</translation> </message> <message> <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> @@ -561,7 +563,7 @@ Address: %4 <name>ClientModel</name> <message> <source>Network Alert</source> - <translation type="unfinished"/> + <translation>تنبيه من الشبكة</translation> </message> </context> <context> @@ -572,7 +574,7 @@ Address: %4 </message> <message> <source>Quantity:</source> - <translation type="unfinished"/> + <translation>الكمية:</translation> </message> <message> <source>Bytes:</source> @@ -580,7 +582,7 @@ Address: %4 </message> <message> <source>Amount:</source> - <translation type="unfinished"/> + <translation>القيمة</translation> </message> <message> <source>Priority:</source> @@ -588,7 +590,7 @@ Address: %4 </message> <message> <source>Fee:</source> - <translation type="unfinished"/> + <translation>رسوم :</translation> </message> <message> <source>Low Output:</source> @@ -628,7 +630,7 @@ Address: %4 </message> <message> <source>Confirmations</source> - <translation type="unfinished"/> + <translation>تأكيد</translation> </message> <message> <source>Confirmed</source> @@ -636,11 +638,11 @@ Address: %4 </message> <message> <source>Priority</source> - <translation type="unfinished"/> + <translation>Ø£Ùضلية</translation> </message> <message> <source>Copy address</source> - <translation> انسخ عنوان</translation> + <translation> انسخ العنوان</translation> </message> <message> <source>Copy label</source> @@ -648,11 +650,11 @@ Address: %4 </message> <message> <source>Copy amount</source> - <translation>نسخ الكمية</translation> + <translation>نسخ القيمة</translation> </message> <message> <source>Copy transaction ID</source> - <translation type="unfinished"/> + <translation>نسخ رقم المعاملة</translation> </message> <message> <source>Lock unspent</source> @@ -664,15 +666,15 @@ Address: %4 </message> <message> <source>Copy quantity</source> - <translation type="unfinished"/> + <translation>نسخ الكمية</translation> </message> <message> <source>Copy fee</source> - <translation type="unfinished"/> + <translation>نسخ الرسوم</translation> </message> <message> <source>Copy after fee</source> - <translation type="unfinished"/> + <translation>نسخ بعد الرسوم</translation> </message> <message> <source>Copy bytes</source> @@ -680,7 +682,7 @@ Address: %4 </message> <message> <source>Copy priority</source> - <translation type="unfinished"/> + <translation>نسخ الاÙضلية</translation> </message> <message> <source>Copy low output</source> @@ -688,19 +690,19 @@ 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> @@ -716,7 +718,7 @@ Address: %4 </message> <message> <source>low</source> - <translation type="unfinished"/> + <translation>منخÙض</translation> </message> <message> <source>lower</source> @@ -732,7 +734,7 @@ Address: %4 </message> <message> <source>none</source> - <translation type="unfinished"/> + <translation>لا شيء</translation> </message> <message> <source>Dust</source> @@ -803,7 +805,7 @@ Address: %4 </message> <message> <source>&Label</source> - <translation type="unfinished"/> + <translation>&وصÙ</translation> </message> <message> <source>The label associated with this address list entry</source> @@ -815,11 +817,11 @@ Address: %4 </message> <message> <source>&Address</source> - <translation>العنوان</translation> + <translation>&العنوان</translation> </message> <message> <source>New receiving address</source> - <translation>عنوان تلقي جديد</translation> + <translation>عنوان أستلام جديد</translation> </message> <message> <source>New sending address</source> @@ -827,8 +829,7 @@ Address: %4 </message> <message> <source>Edit receiving address</source> - <translation>تعديل عنوان التلقي -</translation> + <translation>تعديل عنوان الأستلام</translation> </message> <message> <source>Edit sending address</source> @@ -855,11 +856,11 @@ Address: %4 <name>FreespaceChecker</name> <message> <source>A new data directory will be created.</source> - <translation type="unfinished"/> + <translation>سيتم انشاء دليل بيانات جديد</translation> </message> <message> <source>name</source> - <translation type="unfinished"/> + <translation>الاسم</translation> </message> <message> <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> @@ -871,7 +872,7 @@ Address: %4 </message> <message> <source>Cannot create data directory here.</source> - <translation type="unfinished"/> + <translation>لا يمكن انشاء دليل بيانات هنا .</translation> </message> </context> <context> @@ -925,7 +926,7 @@ Address: %4 <name>Intro</name> <message> <source>Welcome</source> - <translation type="unfinished"/> + <translation>أهلا</translation> </message> <message> <source>Welcome to Bitcoin Core.</source> @@ -941,11 +942,11 @@ Address: %4 </message> <message> <source>Use the default data directory</source> - <translation type="unfinished"/> + <translation>استخدام دليل البانات الاÙتراضي</translation> </message> <message> <source>Use a custom data directory:</source> - <translation type="unfinished"/> + <translation>استخدام دليل بيانات مخصص:</translation> </message> <message> <source>Bitcoin</source> @@ -961,11 +962,11 @@ Address: %4 </message> <message> <source>GB of free space available</source> - <translation type="unfinished"/> + <translation>قيقا بايت مساØØ© متاØØ©</translation> </message> <message> <source>(of %1GB needed)</source> - <translation type="unfinished"/> + <translation>( بØاجة الى 1%قيقا بايت )</translation> </message> </context> <context> @@ -984,11 +985,11 @@ Address: %4 </message> <message> <source>Select payment request file</source> - <translation type="unfinished"/> + <translation>Øدد مل٠طلب الدÙع</translation> </message> <message> <source>Select payment request file to open</source> - <translation type="unfinished"/> + <translation>Øدد مل٠طلب الدÙع Ù„ÙتØÙ‡</translation> </message> </context> <context> @@ -999,7 +1000,7 @@ Address: %4 </message> <message> <source>&Main</source> - <translation>الرئيسي</translation> + <translation>&الرئيسي</translation> </message> <message> <source>Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB.</source> @@ -1007,7 +1008,7 @@ Address: %4 </message> <message> <source>Pay transaction &fee</source> - <translation type="unfinished"/> + <translation>ادÙع &رسوم المعاملة</translation> </message> <message> <source>Automatically start Bitcoin after logging in to the system.</source> @@ -1023,7 +1024,7 @@ Address: %4 </message> <message> <source>MB</source> - <translation type="unfinished"/> + <translation>Ù… ب</translation> </message> <message> <source>Number of script &verification threads</source> @@ -1042,6 +1043,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>عنوان النطاق للطر٠الثالث</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1051,11 +1060,11 @@ Address: %4 </message> <message> <source>&Reset Options</source> - <translation type="unfinished"/> + <translation>&استعادة الخيارات</translation> </message> <message> <source>&Network</source> - <translation type="unfinished"/> + <translation>&الشبكة</translation> </message> <message> <source>(0 = auto, <0 = leave that many cores free)</source> @@ -1063,11 +1072,11 @@ Address: %4 </message> <message> <source>W&allet</source> - <translation type="unfinished"/> + <translation>&Ù…ØÙظة</translation> </message> <message> <source>Expert</source> - <translation type="unfinished"/> + <translation>تصدير</translation> </message> <message> <source>Enable coin &control features</source> @@ -1091,15 +1100,15 @@ Address: %4 </message> <message> <source>Proxy &IP:</source> - <translation type="unfinished"/> + <translation>بروكسي &اي بي:</translation> </message> <message> <source>&Port:</source> - <translation type="unfinished"/> + <translation>&المنÙØ°:</translation> </message> <message> <source>Port of the proxy (e.g. 9050)</source> - <translation type="unfinished"/> + <translation>منÙØ° البروكسي (مثلا 9050)</translation> </message> <message> <source>SOCKS &Version:</source> @@ -1131,11 +1140,11 @@ Address: %4 </message> <message> <source>&Display</source> - <translation type="unfinished"/> + <translation>&عرض</translation> </message> <message> <source>User Interface &language:</source> - <translation type="unfinished"/> + <translation>واجهة المستخدم &اللغة:</translation> </message> <message> <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin.</source> @@ -1175,11 +1184,11 @@ Address: %4 </message> <message> <source>none</source> - <translation type="unfinished"/> + <translation>لا شيء</translation> </message> <message> <source>Confirm options reset</source> - <translation type="unfinished"/> + <translation>تأكيد استعادة الخيارات</translation> </message> <message> <source>Client restart required to activate changes.</source> @@ -1222,7 +1231,7 @@ Address: %4 </message> <message> <source>Pending:</source> - <translation type="unfinished"/> + <translation>معلق:</translation> </message> <message> <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> @@ -1238,11 +1247,11 @@ Address: %4 </message> <message> <source>Total:</source> - <translation type="unfinished"/> + <translation>المجموع:</translation> </message> <message> <source>Your current total balance</source> - <translation type="unfinished"/> + <translation>رصيدك الكلي الØالي</translation> </message> <message> <source><b>Recent transactions</b></source> @@ -1313,7 +1322,7 @@ Address: %4 </message> <message> <source>Bad response from server %1</source> - <translation type="unfinished"/> + <translation>استجابة سيئة من الملقم٪ 1</translation> </message> <message> <source>Payment acknowledged</source> @@ -1343,7 +1352,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> @@ -1355,15 +1364,15 @@ Address: %4 <name>QRImageWidget</name> <message> <source>&Save Image...</source> - <translation type="unfinished"/> + <translation>&ØÙظ الصورة</translation> </message> <message> <source>&Copy Image</source> - <translation type="unfinished"/> + <translation>&نسخ الصورة</translation> </message> <message> <source>Save QR Code</source> - <translation type="unfinished"/> + <translation>ØÙظ رمز الاستجابة السريعة QR</translation> </message> <message> <source>PNG Image (*.png)</source> @@ -1394,7 +1403,7 @@ Address: %4 </message> <message> <source>General</source> - <translation type="unfinished"/> + <translation>عام</translation> </message> <message> <source>Using OpenSSL version</source> @@ -1402,7 +1411,7 @@ Address: %4 </message> <message> <source>Startup time</source> - <translation type="unfinished"/> + <translation>وقت البدء</translation> </message> <message> <source>Network</source> @@ -1442,23 +1451,23 @@ Address: %4 </message> <message> <source>&Network Traffic</source> - <translation type="unfinished"/> + <translation>&Øركة مرور الشبكة</translation> </message> <message> <source>&Clear</source> - <translation type="unfinished"/> + <translation>&مسØ</translation> </message> <message> <source>Totals</source> - <translation type="unfinished"/> + <translation>المجاميع</translation> </message> <message> <source>In:</source> - <translation type="unfinished"/> + <translation>داخل:</translation> </message> <message> <source>Out:</source> - <translation type="unfinished"/> + <translation>خارج:</translation> </message> <message> <source>Build date</source> @@ -1482,7 +1491,7 @@ Address: %4 </message> <message> <source>Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.</source> - <translation type="unfinished"/> + <translation>استخدم اسهم الاعلى Ùˆ الاسÙÙ„ للتنقل بين السجلات Ùˆ <b>Ctrl-L</b> Ù„Ù…Ø³Ø Ø§Ù„Ø´Ø§Ø´Ø©</translation> </message> <message> <source>Type <b>help</b> for an overview of available commands.</source> @@ -1490,46 +1499,46 @@ Address: %4 </message> <message> <source>%1 B</source> - <translation type="unfinished"/> + <translation>1% بايت</translation> </message> <message> <source>%1 KB</source> - <translation type="unfinished"/> + <translation>1% كيلو بايت</translation> </message> <message> <source>%1 MB</source> - <translation type="unfinished"/> + <translation>1% ميقا بايت</translation> </message> <message> <source>%1 GB</source> - <translation type="unfinished"/> + <translation>1% قيقا بايت</translation> </message> <message> <source>%1 m</source> - <translation type="unfinished"/> + <translation>1% دقيقة</translation> </message> <message> <source>%1 h</source> - <translation type="unfinished"/> + <translation>1% ساعة</translation> </message> <message> <source>%1 h %2 m</source> - <translation type="unfinished"/> + <translation>1% ساعة 2% دقيقة</translation> </message> </context> <context> <name>ReceiveCoinsDialog</name> <message> <source>&Amount:</source> - <translation type="unfinished"/> + <translation>&القيمة</translation> </message> <message> <source>&Label:</source> - <translation type="unfinished"/> + <translation>&الوصÙ:</translation> </message> <message> <source>&Message:</source> - <translation type="unfinished"/> + <translation>&رسالة:</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> @@ -1557,15 +1566,15 @@ Address: %4 </message> <message> <source>Clear all fields of the form.</source> - <translation type="unfinished"/> + <translation>Ù…Ø³Ø ÙƒÙ„ Øقول النموذج المطلوبة</translation> </message> <message> <source>Clear</source> - <translation type="unfinished"/> + <translation>مسØ</translation> </message> <message> <source>Requested payments history</source> - <translation type="unfinished"/> + <translation>سجل طلبات الدÙع</translation> </message> <message> <source>&Request payment</source> @@ -1577,7 +1586,7 @@ Address: %4 </message> <message> <source>Show</source> - <translation type="unfinished"/> + <translation>عرض</translation> </message> <message> <source>Remove the selected entries from the list</source> @@ -1585,7 +1594,7 @@ Address: %4 </message> <message> <source>Remove</source> - <translation type="unfinished"/> + <translation>ازل</translation> </message> <message> <source>Copy label</source> @@ -1597,26 +1606,26 @@ Address: %4 </message> <message> <source>Copy amount</source> - <translation>نسخ الكمية</translation> + <translation>نسخ القيمة</translation> </message> </context> <context> <name>ReceiveRequestDialog</name> <message> <source>QR Code</source> - <translation type="unfinished"/> + <translation>رمز كيو ار</translation> </message> <message> <source>Copy &URI</source> - <translation type="unfinished"/> + <translation>نسخ &URI</translation> </message> <message> <source>Copy &Address</source> - <translation type="unfinished"/> + <translation>نسخ &العنوان</translation> </message> <message> <source>&Save Image...</source> - <translation type="unfinished"/> + <translation>&ØÙظ الصورة</translation> </message> <message> <source>Request payment to %1</source> @@ -1628,7 +1637,7 @@ Address: %4 </message> <message> <source>URI</source> - <translation type="unfinished"/> + <translation> URI</translation> </message> <message> <source>Address</source> @@ -1644,7 +1653,7 @@ Address: %4 </message> <message> <source>Message</source> - <translation type="unfinished"/> + <translation>رسالة</translation> </message> <message> <source>Resulting URI too long, try to reduce the text for label / message.</source> @@ -1667,7 +1676,7 @@ Address: %4 </message> <message> <source>Message</source> - <translation type="unfinished"/> + <translation>رسالة</translation> </message> <message> <source>Amount</source> @@ -1679,7 +1688,7 @@ Address: %4 </message> <message> <source>(no message)</source> - <translation type="unfinished"/> + <translation>( لا رسائل )</translation> </message> <message> <source>(no amount)</source> @@ -1702,7 +1711,7 @@ Address: %4 </message> <message> <source>automatically selected</source> - <translation type="unfinished"/> + <translation>اختيار تلقائيا</translation> </message> <message> <source>Insufficient funds!</source> @@ -1710,7 +1719,7 @@ Address: %4 </message> <message> <source>Quantity:</source> - <translation type="unfinished"/> + <translation>الكمية :</translation> </message> <message> <source>Bytes:</source> @@ -1718,15 +1727,15 @@ Address: %4 </message> <message> <source>Amount:</source> - <translation type="unfinished"/> + <translation>القيمة :</translation> </message> <message> <source>Priority:</source> - <translation type="unfinished"/> + <translation>اÙضلية :</translation> </message> <message> <source>Fee:</source> - <translation type="unfinished"/> + <translation>رسوم :</translation> </message> <message> <source>Low Output:</source> @@ -1734,11 +1743,11 @@ Address: %4 </message> <message> <source>After Fee:</source> - <translation type="unfinished"/> + <translation>بعد الرسوم :</translation> </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> @@ -1754,7 +1763,7 @@ Address: %4 </message> <message> <source>Add &Recipient</source> - <translation type="unfinished"/> + <translation>أضاÙØ© &مستلم</translation> </message> <message> <source>Clear all fields of the form.</source> @@ -1774,7 +1783,7 @@ Address: %4 </message> <message> <source>S&end</source> - <translation type="unfinished"/> + <translation>&ارسال</translation> </message> <message> <source>Confirm send coins</source> @@ -1782,23 +1791,23 @@ Address: %4 </message> <message> <source>%1 to %2</source> - <translation type="unfinished"/> + <translation>1% الى 2%</translation> </message> <message> <source>Copy quantity</source> - <translation type="unfinished"/> + <translation>نسخ الكمية </translation> </message> <message> <source>Copy amount</source> - <translation>نسخ الكمية</translation> + <translation>نسخ القيمة</translation> </message> <message> <source>Copy fee</source> - <translation type="unfinished"/> + <translation>نسخ الرسوم</translation> </message> <message> <source>Copy after fee</source> - <translation type="unfinished"/> + <translation>نسخ بعد الرسوم</translation> </message> <message> <source>Copy bytes</source> @@ -1806,7 +1815,7 @@ Address: %4 </message> <message> <source>Copy priority</source> - <translation type="unfinished"/> + <translation>نسخ الاÙضلية</translation> </message> <message> <source>Copy low output</source> @@ -1814,15 +1823,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> @@ -1834,11 +1843,11 @@ Address: %4 </message> <message> <source>The amount exceeds your balance.</source> - <translation type="unfinished"/> + <translation>القيمة تتجاوز رصيدك</translation> </message> <message> <source>The total exceeds your balance when the %1 transaction fee is included.</source> - <translation type="unfinished"/> + <translation>المجموع يتجاوز رصيدك عندما يتم اضاÙØ© 1% رسوم العملية</translation> </message> <message> <source>Duplicate address found, can only send to each address once per send operation.</source> @@ -1889,7 +1898,7 @@ Address: %4 </message> <message> <source>Pay &To:</source> - <translation>ادÙع الى </translation> + <translation>ادÙع &الى :</translation> </message> <message> <source>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -1901,7 +1910,7 @@ Address: %4 </message> <message> <source>&Label:</source> - <translation type="unfinished"/> + <translation>&وص٠:</translation> </message> <message> <source>Choose previously used address</source> @@ -1917,7 +1926,7 @@ Address: %4 </message> <message> <source>Paste address from clipboard</source> - <translation>انسخ العنوان من لوØØ© المÙاتيØ</translation> + <translation>الصق العنوان من لوØØ© المÙاتيØ</translation> </message> <message> <source>Alt+P</source> @@ -1964,7 +1973,7 @@ Address: %4 </message> <message> <source>Do not shut down the computer until this window disappears.</source> - <translation type="unfinished"/> + <translation>لا توق٠عمل الكمبيوتر Øتى تختÙÙŠ هذه الناÙذة</translation> </message> </context> <context> @@ -1975,7 +1984,7 @@ Address: %4 </message> <message> <source>&Sign Message</source> - <translation type="unfinished"/> + <translation>&توقيع الرسالة</translation> </message> <message> <source>You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> @@ -2003,11 +2012,11 @@ Address: %4 </message> <message> <source>Enter the message you want to sign here</source> - <translation type="unfinished"/> + <translation>ادخل الرسالة التي تريد توقيعها هنا</translation> </message> <message> <source>Signature</source> - <translation type="unfinished"/> + <translation>التوقيع</translation> </message> <message> <source>Copy the current signature to the system clipboard</source> @@ -2015,11 +2024,11 @@ Address: %4 </message> <message> <source>Sign the message to prove you own this Bitcoin address</source> - <translation type="unfinished"/> + <translation>وقع الرسالة لتثبت انك تمتلك عنوان البت كوين هذا</translation> </message> <message> <source>Sign &Message</source> - <translation type="unfinished"/> + <translation>توقيع $الرسالة</translation> </message> <message> <source>Reset all sign message fields</source> @@ -2031,7 +2040,7 @@ Address: %4 </message> <message> <source>&Verify Message</source> - <translation type="unfinished"/> + <translation>&تØقق رسالة</translation> </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> @@ -2047,7 +2056,7 @@ Address: %4 </message> <message> <source>Verify &Message</source> - <translation type="unfinished"/> + <translation>تØقق &الرسالة</translation> </message> <message> <source>Reset all verify message fields</source> @@ -2059,7 +2068,7 @@ Address: %4 </message> <message> <source>Click "Sign Message" to generate signature</source> - <translation type="unfinished"/> + <translation>اضغط "توقيع الرسالة" لتوليد التوقيع</translation> </message> <message> <source>The entered address is invalid.</source> @@ -2075,7 +2084,7 @@ Address: %4 </message> <message> <source>Wallet unlock was cancelled.</source> - <translation type="unfinished"/> + <translation>تم الغاء عملية ÙØªØ Ø§Ù„Ù…ØÙظة</translation> </message> <message> <source>Private key for the entered address is not available.</source> @@ -2095,7 +2104,7 @@ Address: %4 </message> <message> <source>Please check the signature and try again.</source> - <translation type="unfinished"/> + <translation>Ùضلا تاكد من التوقيع ÙˆØاول مرة اخرى</translation> </message> <message> <source>The signature did not match the message digest.</source> @@ -2140,7 +2149,7 @@ Address: %4 </message> <message> <source>conflicted</source> - <translation type="unfinished"/> + <translation>يتعارض</translation> </message> <message> <source>%1/offline</source> @@ -2188,7 +2197,7 @@ Address: %4 </message> <message> <source>label</source> - <translation type="unfinished"/> + <translation>علامة</translation> </message> <message> <source>Credit</source> @@ -2208,7 +2217,7 @@ Address: %4 </message> <message> <source>Transaction fee</source> - <translation>رسوم التØويل</translation> + <translation>رسوم المعاملة</translation> </message> <message> <source>Net amount</source> @@ -2216,7 +2225,7 @@ Address: %4 </message> <message> <source>Message</source> - <translation type="unfinished"/> + <translation>رسالة </translation> </message> <message> <source>Comment</source> @@ -2228,7 +2237,7 @@ Address: %4 </message> <message> <source>Merchant</source> - <translation type="unfinished"/> + <translation>تاجر</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 "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> @@ -2260,7 +2269,7 @@ Address: %4 </message> <message> <source>, has not been successfully broadcast yet</source> - <translation>لم يتم Øتى الآن البث بنجاØ</translation> + <translation>, لم يتم Øتى الآن البث بنجاØ</translation> </message> <message numerus="yes"> <source>Open for %n more block(s)</source> @@ -2413,7 +2422,7 @@ Address: %4 </message> <message> <source>Range...</source> - <translation>v</translation> + <translation>المدى...</translation> </message> <message> <source>Received with</source> @@ -2441,7 +2450,7 @@ Address: %4 </message> <message> <source>Min amount</source> - <translation type="unfinished"/> + <translation>الØد الأدنى</translation> </message> <message> <source>Copy address</source> @@ -2457,7 +2466,7 @@ Address: %4 </message> <message> <source>Copy transaction ID</source> - <translation type="unfinished"/> + <translation>نسخ رقم العملية</translation> </message> <message> <source>Edit label</source> @@ -2465,7 +2474,7 @@ Address: %4 </message> <message> <source>Show transaction details</source> - <translation type="unfinished"/> + <translation>عرض تÙاصيل المعاملة</translation> </message> <message> <source>Export Transaction History</source> @@ -2473,7 +2482,7 @@ Address: %4 </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> @@ -2481,7 +2490,7 @@ Address: %4 </message> <message> <source>Exporting Successful</source> - <translation>Ù†Ø¬Ø Ø§Ù„Ø§Ø³ØªØ®Ø±Ø§Ø¬</translation> + <translation>Ù†Ø¬Ø Ø§Ù„ØªØµØ¯ÙŠØ±</translation> </message> <message> <source>The transaction history was successfully saved to %1.</source> @@ -2521,7 +2530,7 @@ Address: %4 </message> <message> <source>Range:</source> - <translation type="unfinished"/> + <translation>المدى:</translation> </message> <message> <source>to</source> @@ -2546,7 +2555,7 @@ Address: %4 <name>WalletView</name> <message> <source>&Export</source> - <translation type="unfinished"/> + <translation>&تصدير</translation> </message> <message> <source>Export the data in the current tab to a file</source> @@ -2554,7 +2563,7 @@ Address: %4 </message> <message> <source>Backup Wallet</source> - <translation type="unfinished"/> + <translation>نسخ اØتياط للمØÙظة</translation> </message> <message> <source>Wallet Data (*.dat)</source> @@ -2562,7 +2571,7 @@ Address: %4 </message> <message> <source>Backup Failed</source> - <translation type="unfinished"/> + <translation>Ùشل النسخ الاØتياطي</translation> </message> <message> <source>There was an error trying to save the wallet data to %1.</source> @@ -2574,7 +2583,7 @@ Address: %4 </message> <message> <source>Backup Successful</source> - <translation type="unfinished"/> + <translation>Ù†Ø¬Ø§Ø Ø§Ù„Ù†Ø³Ø® الاØتياطي</translation> </message> </context> <context> @@ -2605,7 +2614,7 @@ Address: %4 </message> <message> <source>Specify data directory</source> - <translation>Øدد موقع مجلد المعلومات او data directory</translation> + <translation>Øدد مجلد المعلومات</translation> </message> <message> <source>Listen for connections on <port> (default: 8333 or testnet: 18333)</source> @@ -2859,15 +2868,15 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Error: Disk space is low!</source> - <translation type="unfinished"/> + <translation>تØذير: مساØØ© القرص منخÙضة</translation> </message> <message> <source>Error: Wallet locked, unable to create transaction!</source> - <translation type="unfinished"/> + <translation>تØذير: المØÙظة مغلقة , لا تستطيع تنÙيذ المعاملة</translation> </message> <message> <source>Error: system error: </source> - <translation type="unfinished"/> + <translation>خطأ: خطأ ÙÙŠ النظام:</translation> </message> <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> @@ -2951,7 +2960,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Invalid -onion address: '%s'</source> - <translation type="unfinished"/> + <translation>عنوان اونيون غير صØÙŠØ : '%s'</translation> </message> <message> <source>Not enough file descriptors available.</source> @@ -3007,7 +3016,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Verifying wallet...</source> - <translation type="unfinished"/> + <translation>التØقق من المØÙظة ...</translation> </message> <message> <source>Wait for RPC server to start</source> @@ -3019,7 +3028,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3051,7 +3060,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Information</source> - <translation type="unfinished"/> + <translation>معلومات</translation> </message> <message> <source>Invalid amount for -minrelaytxfee=<amount>: '%s'</source> @@ -3151,7 +3160,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Signing transaction failed</source> - <translation type="unfinished"/> + <translation>Ùشل توقيع المعاملة</translation> </message> <message> <source>Specify connection timeout in milliseconds (default: 5000)</source> @@ -3163,19 +3172,19 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>System error: </source> - <translation type="unfinished"/> + <translation>خطأ ÙÙŠ النظام :</translation> </message> <message> <source>Transaction amount too small</source> - <translation type="unfinished"/> + <translation>قيمة العملية صغيره جدا</translation> </message> <message> <source>Transaction amounts must be positive</source> - <translation type="unfinished"/> + <translation>يجب ان يكون قيمة العملية بالموجب</translation> </message> <message> <source>Transaction too large</source> - <translation type="unfinished"/> + <translation>المعاملة طويلة جدا</translation> </message> <message> <source>Use UPnP to map the listening port (default: 0)</source> @@ -3191,11 +3200,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Warning</source> - <translation type="unfinished"/> + <translation>تØذير</translation> </message> <message> <source>Warning: This version is obsolete, upgrade required!</source> - <translation type="unfinished"/> + <translation>تØذير : هذا الاصدار قديم , يتطلب التØديث</translation> </message> <message> <source>Zapping all transactions from wallet...</source> @@ -3231,7 +3240,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Upgrade wallet to latest format</source> - <translation type="unfinished"/> + <translation>تØديث المØÙظة للنسخة الاخيرة</translation> </message> <message> <source>Set key pool size to <n> (default: 100)</source> @@ -3251,7 +3260,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Server private key (default: server.pem)</source> - <translation type="unfinished"/> + <translation>المÙØªØ§Ø Ø§Ù„Ø®Ø§Øµ بالسيرÙر (default: server.pem)</translation> </message> <message> <source>This help message</source> @@ -3287,7 +3296,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Invalid -proxy address: '%s'</source> - <translation type="unfinished"/> + <translation>عنوان البروكسي غير صØÙŠØ : '%s'</translation> </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> @@ -3311,11 +3320,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Invalid amount</source> - <translation type="unfinished"/> + <translation>قيمة غير صØÙŠØØ©</translation> </message> <message> <source>Insufficient funds</source> - <translation type="unfinished"/> + <translation>اموال غير كاÙية</translation> </message> <message> <source>Loading block index...</source> @@ -3335,7 +3344,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Cannot write default address</source> - <translation type="unfinished"/> + <translation>لايمكن كتابة العنوان الاÙتراضي</translation> </message> <message> <source>Rescanning...</source> @@ -3347,7 +3356,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>To use the %s option</source> - <translation type="unfinished"/> + <translation>لاستخدام %s الخيار</translation> </message> <message> <source>Error</source> diff --git a/src/qt/locale/bitcoin_be_BY.ts b/src/qt/locale/bitcoin_be_BY.ts index f7beb808d1..c384aa6d2d 100644 --- a/src/qt/locale/bitcoin_be_BY.ts +++ b/src/qt/locale/bitcoin_be_BY.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="be_BY" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="be_BY" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1043,6 +1043,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1344,7 +1352,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts index 6b94dc8978..367e223784 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="bg" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="bg" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1044,6 +1044,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1345,7 +1353,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_bs.ts b/src/qt/locale/bitcoin_bs.ts index 01c37b0278..2ec28af777 100644 --- a/src/qt/locale/bitcoin_bs.ts +++ b/src/qt/locale/bitcoin_bs.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="bs" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="bs" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts index 592cb337d5..c225967cac 100644 --- a/src/qt/locale/bitcoin_ca.ts +++ b/src/qt/locale/bitcoin_ca.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ca" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ca" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_ca@valencia.ts b/src/qt/locale/bitcoin_ca@valencia.ts index 053cc82ebb..b36d6b7d67 100644 --- a/src/qt/locale/bitcoin_ca@valencia.ts +++ b/src/qt/locale/bitcoin_ca@valencia.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ca@valencia" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ca@valencia" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts index f01e48a435..5bf7fbfba7 100644 --- a/src/qt/locale/bitcoin_ca_ES.ts +++ b/src/qt/locale/bitcoin_ca_ES.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ca_ES" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ca_ES" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_cmn.ts b/src/qt/locale/bitcoin_cmn.ts index 402ce7cb10..696cbedd0a 100644 --- a/src/qt/locale/bitcoin_cmn.ts +++ b/src/qt/locale/bitcoin_cmn.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="cmn" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="cmn" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index f77e7f34db..6cc783b59e 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="cs" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="cs" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -333,7 +333,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použità v Open </message> <message> <source>Open &URI...</source> - <translation type="unfinished"/> + <translation>NaÄÃst &URI...</translation> </message> <message> <source>Importing blocks from disk...</source> @@ -433,7 +433,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použità v Open </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished"/> + <translation>Požaduj platby (generuje QR kódy a bitcoin: URI)</translation> </message> <message> <source>&About Bitcoin Core</source> @@ -441,15 +441,15 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použità v Open </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished"/> + <translation>Ukaž seznam použitých odesÃlacÃch adres a jejich oznaÄenÃ</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished"/> + <translation>Ukaž seznam použitých pÅ™ijÃmacÃch adres a jejich oznaÄenÃ</translation> </message> <message> <source>Open a bitcoin: URI or payment request</source> - <translation type="unfinished"/> + <translation>NaÄti bitcoin: URI nebo platebnà požadavek</translation> </message> <message> <source>&Command-line options</source> @@ -457,7 +457,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použità v Open </message> <message> <source>Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options</source> - <translation>Seznam argumentů Bitcoinu pro pÅ™Ãkazovou řádku zÃskáš v nápovÄ›dÄ› Bitcoinu Core.</translation> + <translation>Seznam argumentů Bitcoinu pro pÅ™Ãkazovou řádku zÃskáš v nápovÄ›dÄ› Bitcoinu Core</translation> </message> <message> <source>Bitcoin client</source> @@ -497,7 +497,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použità v Open </message> <message numerus="yes"> <source>%n year(s)</source> - <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation> + <translation><numerusform>rok</numerusform><numerusform>%n roky</numerusform><numerusform>%n roků</numerusform></translation> </message> <message> <source>%1 behind</source> @@ -579,7 +579,7 @@ Adresa: %4 </message> <message> <source>Quantity:</source> - <translation type="unfinished"/> + <translation>PoÄet:</translation> </message> <message> <source>Bytes:</source> @@ -599,11 +599,11 @@ Adresa: %4 </message> <message> <source>Low Output:</source> - <translation type="unfinished"/> + <translation>Malý výstup:</translation> </message> <message> <source>After Fee:</source> - <translation type="unfinished"/> + <translation>ÄŒistá Äástka:</translation> </message> <message> <source>Change:</source> @@ -611,15 +611,15 @@ Adresa: %4 </message> <message> <source>(un)select all</source> - <translation type="unfinished"/> + <translation>(od)oznaÄit vÅ¡echny</translation> </message> <message> <source>Tree mode</source> - <translation type="unfinished"/> + <translation>Zobrazit jako strom</translation> </message> <message> <source>List mode</source> - <translation type="unfinished"/> + <translation>Vypsat jako seznam</translation> </message> <message> <source>Amount</source> @@ -663,15 +663,15 @@ Adresa: %4 </message> <message> <source>Lock unspent</source> - <translation type="unfinished"/> + <translation>Zamkni neutracené</translation> </message> <message> <source>Unlock unspent</source> - <translation type="unfinished"/> + <translation>Odemkni k utracenÃ</translation> </message> <message> <source>Copy quantity</source> - <translation type="unfinished"/> + <translation>KopÃruj poÄet</translation> </message> <message> <source>Copy fee</source> @@ -679,7 +679,7 @@ Adresa: %4 </message> <message> <source>Copy after fee</source> - <translation type="unfinished"/> + <translation>KopÃruj Äistou Äástku</translation> </message> <message> <source>Copy bytes</source> @@ -691,7 +691,7 @@ Adresa: %4 </message> <message> <source>Copy low output</source> - <translation type="unfinished"/> + <translation>KopÃruj malý výstup</translation> </message> <message> <source>Copy change</source> @@ -699,47 +699,47 @@ Adresa: %4 </message> <message> <source>highest</source> - <translation type="unfinished"/> + <translation>nejvyÅ¡Å¡Ã</translation> </message> <message> <source>higher</source> - <translation type="unfinished"/> + <translation>vyÅ¡Å¡Ã</translation> </message> <message> <source>high</source> - <translation type="unfinished"/> + <translation>vysoká</translation> </message> <message> <source>medium-high</source> - <translation type="unfinished"/> + <translation>vyÅ¡Å¡Ã stÅ™ednÃ</translation> </message> <message> <source>medium</source> - <translation type="unfinished"/> + <translation>stÅ™ednÃ</translation> </message> <message> <source>low-medium</source> - <translation type="unfinished"/> + <translation>nižšà stÅ™ednÃ</translation> </message> <message> <source>low</source> - <translation type="unfinished"/> + <translation>nÃzká</translation> </message> <message> <source>lower</source> - <translation type="unfinished"/> + <translation>nižšÃ</translation> </message> <message> <source>lowest</source> - <translation type="unfinished"/> + <translation>nejnižšÃ</translation> </message> <message> <source>(%1 locked)</source> - <translation type="unfinished"/> + <translation>(%1 zamÄeno)</translation> </message> <message> <source>none</source> - <translation type="unfinished"/> + <translation>žádná</translation> </message> <message> <source>Dust</source> @@ -747,11 +747,11 @@ Adresa: %4 </message> <message> <source>yes</source> - <translation type="unfinished"/> + <translation>ano</translation> </message> <message> <source>no</source> - <translation type="unfinished"/> + <translation>ne</translation> </message> <message> <source>This label turns red, if the transaction size is greater than 1000 bytes.</source> @@ -759,11 +759,11 @@ Adresa: %4 </message> <message> <source>This means a fee of at least %1 per kB is required.</source> - <translation type="unfinished"/> + <translation>To znamená, že je vyžadován poplatek alespoň %1 za kB.</translation> </message> <message> <source>Can vary +/- 1 byte per input.</source> - <translation type="unfinished"/> + <translation>Může se liÅ¡it o +/– 1 bajt na každý vstup.</translation> </message> <message> <source>Transactions with higher priority are more likely to get included into a block.</source> @@ -1048,6 +1048,14 @@ Adresa: %4 <translation>IP adresa proxy (napÅ™. 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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1181,7 +1189,7 @@ Adresa: %4 </message> <message> <source>none</source> - <translation type="unfinished"/> + <translation>žádná</translation> </message> <message> <source>Confirm options reset</source> @@ -1189,7 +1197,7 @@ Adresa: %4 </message> <message> <source>Client restart required to activate changes.</source> - <translation type="unfinished"/> + <translation>K aktivaci zmÄ›n je potÅ™eba restartovat klienta.</translation> </message> <message> <source>Client will be shutdown, do you want to proceed?</source> @@ -1291,7 +1299,7 @@ Adresa: %4 </message> <message> <source>Payment request fetch URL is invalid: %1</source> - <translation type="unfinished"/> + <translation>Zdrojová URL platebnÃho požadavku nenà platná: %1</translation> </message> <message> <source>Payment request file handling</source> @@ -1303,7 +1311,7 @@ Adresa: %4 </message> <message> <source>Unverified payment requests to custom payment scripts are unsupported.</source> - <translation type="unfinished"/> + <translation>Neověřené platebnà požadavky k uživatelským platebnÃm skriptům nejsou podporované.</translation> </message> <message> <source>Refund from %1</source> @@ -1349,7 +1357,7 @@ Adresa: %4 <translation>Chyba: Neplatná kombinace -regtest a -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation>Bitcoin Core jeÅ¡tÄ› bezpeÄnÄ› neskonÄil...</translation> </message> <message> @@ -1563,7 +1571,7 @@ Adresa: %4 </message> <message> <source>Clear all fields of the form.</source> - <translation type="unfinished"/> + <translation>Smaže vÅ¡echny pole formuláře.</translation> </message> <message> <source>Clear</source> @@ -1591,7 +1599,7 @@ Adresa: %4 </message> <message> <source>Remove</source> - <translation type="unfinished"/> + <translation>Odstranit</translation> </message> <message> <source>Copy label</source> @@ -1614,15 +1622,15 @@ Adresa: %4 </message> <message> <source>Copy &URI</source> - <translation type="unfinished"/> + <translation>KopÃruj &URI</translation> </message> <message> <source>Copy &Address</source> - <translation type="unfinished"/> + <translation>KopÃruj &adresu</translation> </message> <message> <source>&Save Image...</source> - <translation>&Ulož Obrázek...</translation> + <translation>&Ulož obrázek...</translation> </message> <message> <source>Request payment to %1</source> @@ -1630,7 +1638,7 @@ Adresa: %4 </message> <message> <source>Payment information</source> - <translation type="unfinished"/> + <translation>Informace o platbÄ›</translation> </message> <message> <source>URI</source> @@ -1704,19 +1712,19 @@ Adresa: %4 </message> <message> <source>Inputs...</source> - <translation type="unfinished"/> + <translation>Vstupy...</translation> </message> <message> <source>automatically selected</source> - <translation type="unfinished"/> + <translation>automaticky vybrané</translation> </message> <message> <source>Insufficient funds!</source> - <translation type="unfinished"/> + <translation>Nedostatek prostÅ™edků!</translation> </message> <message> <source>Quantity:</source> - <translation type="unfinished"/> + <translation>PoÄet:</translation> </message> <message> <source>Bytes:</source> @@ -1736,11 +1744,11 @@ Adresa: %4 </message> <message> <source>Low Output:</source> - <translation type="unfinished"/> + <translation>Malý výstup:</translation> </message> <message> <source>After Fee:</source> - <translation type="unfinished"/> + <translation>ÄŒistá Äástka:</translation> </message> <message> <source>Change:</source> @@ -1764,7 +1772,7 @@ Adresa: %4 </message> <message> <source>Clear all fields of the form.</source> - <translation type="unfinished"/> + <translation>Smaže vÅ¡echny pole formuláře.</translation> </message> <message> <source>Clear &All</source> @@ -1792,7 +1800,7 @@ Adresa: %4 </message> <message> <source>Copy quantity</source> - <translation type="unfinished"/> + <translation>KopÃruj poÄet</translation> </message> <message> <source>Copy amount</source> @@ -1804,7 +1812,7 @@ Adresa: %4 </message> <message> <source>Copy after fee</source> - <translation type="unfinished"/> + <translation>KopÃruj Äistou Äástku</translation> </message> <message> <source>Copy bytes</source> @@ -1816,7 +1824,7 @@ Adresa: %4 </message> <message> <source>Copy low output</source> - <translation type="unfinished"/> + <translation>KopÃruj malý výstup</translation> </message> <message> <source>Copy change</source> @@ -1824,7 +1832,7 @@ Adresa: %4 </message> <message> <source>Total Amount %1 (= %2)</source> - <translation type="unfinished"/> + <translation>Celková Äástka %1 (= %2)</translation> </message> <message> <source>or</source> @@ -1872,15 +1880,15 @@ Adresa: %4 </message> <message> <source>Are you sure you want to send?</source> - <translation type="unfinished"/> + <translation>Opravdu chcete odeslat %1?</translation> </message> <message> <source>added as transaction fee</source> - <translation type="unfinished"/> + <translation>pÅ™idán jako transakÄnà poplatek</translation> </message> <message> <source>Payment request expired</source> - <translation type="unfinished"/> + <translation>Platebnà požadavek vyprÅ¡el</translation> </message> <message> <source>Invalid payment address %1</source> @@ -1911,7 +1919,7 @@ Adresa: %4 </message> <message> <source>Choose previously used address</source> - <translation type="unfinished"/> + <translation>Vyber již použitou adresu</translation> </message> <message> <source>This is a normal payment.</source> @@ -1939,7 +1947,7 @@ Adresa: %4 </message> <message> <source>This is a verified payment request.</source> - <translation type="unfinished"/> + <translation>Toto je ověřený požadavek k platbÄ›.</translation> </message> <message> <source>Enter a label for this address to add it to the list of used addresses</source> @@ -1951,11 +1959,11 @@ Adresa: %4 </message> <message> <source>This is an unverified payment request.</source> - <translation type="unfinished"/> + <translation>Toto je neověřený požadavek k platbÄ›.</translation> </message> <message> <source>Pay To:</source> - <translation type="unfinished"/> + <translation>Komu:</translation> </message> <message> <source>Memo:</source> @@ -1993,7 +2001,7 @@ Adresa: %4 </message> <message> <source>Choose previously used address</source> - <translation type="unfinished"/> + <translation>Vyber již použitou adresu</translation> </message> <message> <source>Alt+A</source> @@ -2823,7 +2831,7 @@ napÅ™Ãklad: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Connect through SOCKS proxy</source> - <translation type="unfinished"/> + <translation>PÅ™ipojit se pÅ™es SOCKS proxy</translation> </message> <message> <source>Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)</source> @@ -2831,7 +2839,7 @@ napÅ™Ãklad: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Connection options:</source> - <translation type="unfinished"/> + <translation>Možnosti pÅ™ipojenÃ:</translation> </message> <message> <source>Corrupted block database detected</source> @@ -2839,7 +2847,7 @@ napÅ™Ãklad: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Debugging/Testing options:</source> - <translation type="unfinished"/> + <translation>Možnosti ladÄ›nÃ/testovánÃ:</translation> </message> <message> <source>Disable safemode, override a real safe mode event (default: 0)</source> @@ -2851,7 +2859,7 @@ napÅ™Ãklad: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Do not load the wallet and disable wallet RPC calls</source> - <translation type="unfinished"/> + <translation>NenaÄÃtat peněženku a vypnout jejà RPC volánÃ</translation> </message> <message> <source>Do you want to rebuild the block database now?</source> @@ -3035,7 +3043,7 @@ napÅ™Ãklad: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Wallet options:</source> - <translation type="unfinished"/> + <translation>Možnosti peněženky:</translation> </message> <message> <source>Warning: Deprecated argument -debugnet ignored, use -debug=net</source> @@ -3119,7 +3127,7 @@ napÅ™Ãklad: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>RPC server options:</source> - <translation type="unfinished"/> + <translation>Možnosti RPC serveru:</translation> </message> <message> <source>Randomly drop 1 of every <n> network messages</source> diff --git a/src/qt/locale/bitcoin_cy.ts b/src/qt/locale/bitcoin_cy.ts index b7624f07f2..d2f41739cb 100644 --- a/src/qt/locale/bitcoin_cy.ts +++ b/src/qt/locale/bitcoin_cy.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="cy" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="cy" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts index 3d89d2e5c5..a0514035fd 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -1,13 +1,13 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="da" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="da" version="2.1"> <context> <name>AboutDialog</name> <message> <source>About Bitcoin Core</source> - <translation type="unfinished"/> + <translation>Om Bitcoin Core</translation> </message> <message> <source><b>Bitcoin Core</b> version</source> - <translation type="unfinished"/> + <translation><b>Bitcoin Core</b> 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,23 +48,23 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open </message> <message> <source>&New</source> - <translation>&Ny</translation> + <translation>Ny</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>Kopier den valgte adresse til systemets udklipsholder</translation> + <translation>Kopiér den valgte adresse til systemets udklipsholder</translation> </message> <message> <source>&Copy</source> - <translation>&Kopiér</translation> + <translation>Kopiér</translation> </message> <message> <source>C&lose</source> - <translation type="unfinished"/> + <translation>Luk</translation> </message> <message> <source>&Copy Address</source> - <translation>Kopier adresse</translation> + <translation>Kopiér adresse</translation> </message> <message> <source>Delete the currently selected address from the list</source> @@ -76,7 +76,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open </message> <message> <source>&Export</source> - <translation>Eksporter</translation> + <translation>Eksportér</translation> </message> <message> <source>&Delete</source> @@ -84,23 +84,23 @@ 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&hoose</source> - <translation type="unfinished"/> + <translation>Vælg</translation> </message> <message> <source>Sending addresses</source> - <translation type="unfinished"/> + <translation>Afsendelsesadresser</translation> </message> <message> <source>Receiving addresses</source> - <translation type="unfinished"/> + <translation>Modtagelsesadresser</translation> </message> <message> <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> @@ -108,19 +108,19 @@ 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 &Label</source> - <translation>Kopier mærkat</translation> + <translation>Kopiér mærkat</translation> </message> <message> <source>&Edit</source> - <translation>Rediger</translation> + <translation>Redigér</translation> </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> @@ -174,7 +174,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open </message> <message> <source>Encrypt wallet</source> - <translation>Krypter tegnebog</translation> + <translation>Kryptér tegnebog</translation> </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> @@ -190,7 +190,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open </message> <message> <source>Decrypt wallet</source> - <translation>Dekrypter tegnebog</translation> + <translation>Dekryptér tegnebog</translation> </message> <message> <source>Change passphrase</source> @@ -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> @@ -261,11 +261,11 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open <name>BitcoinGUI</name> <message> <source>Sign &message...</source> - <translation>Underskriv besked...</translation> + <translation>Underskriv besked …</translation> </message> <message> <source>Synchronizing with network...</source> - <translation>Synkroniserer med netværk...</translation> + <translation>Synkroniserer med netværk …</translation> </message> <message> <source>&Overview</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> @@ -309,39 +309,39 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open </message> <message> <source>&Options...</source> - <translation>Indstillinger...</translation> + <translation>Indstillinger …</translation> </message> <message> <source>&Encrypt Wallet...</source> - <translation>Krypter tegnebog...</translation> + <translation>Kryptér tegnebog …</translation> </message> <message> <source>&Backup Wallet...</source> - <translation>Sikkerhedskopier tegnebog...</translation> + <translation>Sikkerhedskopiér tegnebog …</translation> </message> <message> <source>&Change Passphrase...</source> - <translation>Skift adgangskode...</translation> + <translation>Skift adgangskode …</translation> </message> <message> <source>&Sending addresses...</source> - <translation type="unfinished"/> + <translation>Afsendelsesadresser …</translation> </message> <message> <source>&Receiving addresses...</source> - <translation type="unfinished"/> + <translation>Modtagelsesadresser …</translation> </message> <message> <source>Open &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> @@ -349,7 +349,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open </message> <message> <source>Modify configuration options for Bitcoin</source> - <translation>Rediger konfigurationsindstillinger af Bitcoin</translation> + <translation>Redigér konfigurationsindstillinger for Bitcoin</translation> </message> <message> <source>Backup wallet to another location</source> @@ -369,7 +369,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open </message> <message> <source>&Verify message...</source> - <translation>Verificér besked...</translation> + <translation>Verificér besked …</translation> </message> <message> <source>Bitcoin</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>&File</source> @@ -413,7 +413,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open </message> <message> <source>&Settings</source> - <translation>Indstillinger</translation> + <translation>Opsætning</translation> </message> <message> <source>&Help</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 "bitcoin:"-URI'er)</translation> </message> <message> <source>&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 "bitcoin:"-URI eller betalingsforespørgsel</translation> </message> <message> <source>&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> @@ -465,11 +465,11 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network</source> - <translation><numerusform>%n aktiv(e) forbindelse(r) til Bitcoin-netværket</numerusform><numerusform>%n aktiv(e) forbindelse(r) til Bitcoin-netværket</numerusform></translation> + <translation><numerusform>%n aktiv forbindelse til Bitcoin-netværket</numerusform><numerusform>%n aktive forbindelser til Bitcoin-netværket</numerusform></translation> </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> @@ -529,7 +529,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open </message> <message> <source>Catching up...</source> - <translation>Indhenter...</translation> + <translation>Indhenter …</translation> </message> <message> <source>Sent transaction</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 "medium".</source> - <translation type="unfinished"/> + <translation>Dette mærkat bliver rødt, hvis prioriteten er mindre end "medium".</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,18 +795,18 @@ 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> <name>EditAddressDialog</name> <message> <source>Edit Address</source> - <translation>Rediger adresse</translation> + <translation>Redigér adresse</translation> </message> <message> <source>&Label</source> @@ -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>&Address</source> @@ -834,11 +834,11 @@ Adresse: %4 </message> <message> <source>Edit receiving address</source> - <translation>Rediger modtagelsesadresse</translation> + <translation>Redigér modtagelsesadresse</translation> </message> <message> <source>Edit sending address</source> - <translation>Rediger afsendelsesadresse</translation> + <translation>Redigér afsendelsesadresse</translation> </message> <message> <source>The entered address "%1" is already in the address book.</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 "de_DE" (default: system locale)</source> - <translation>Angiv sprog, f.eks "de_DE" (standard: systemlokalitet)</translation> + <translation>Angiv sprog, fx "da_DK" (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 "%1" can not be created.</source> - <translation type="unfinished"/> + <translation>Fejl: Angivet datamappe "%1" 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> @@ -1017,39 +1017,47 @@ Adresse: %4 </message> <message> <source>Automatically start Bitcoin after logging in to the system.</source> - <translation>Start Bitcoin automatisk, nÃ¥r der logges ind pÃ¥ systemet</translation> + <translation>Start Bitcoin automatisk, nÃ¥r der logges ind pÃ¥ systemet.</translation> </message> <message> <source>&Start Bitcoin on system login</source> - <translation>Start Bitcoin, nÃ¥r systemet startes</translation> + <translation>Start Bitcoin ved systemlogin</translation> </message> <message> <source>Size of &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 &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>&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>Tredjeparts-URL'er (fx et blokhÃ¥ndteringsværktøj), der vises i transaktionsfanen som genvejsmenupunkter. %s i URL'en erstattes med transaktionens hash. Flere URL'er separeres med en lodret streg |.</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>Tredjeparts-transaktions-URL'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> @@ -1065,35 +1073,35 @@ Adresse: %4 </message> <message> <source>(0 = auto, <0 = leave that many cores free)</source> - <translation type="unfinished"/> + <translation>(0 = auto, <0 = efterlad sÃ¥ mange kerner fri)</translation> </message> <message> <source>W&allet</source> - <translation type="unfinished"/> + <translation>Tegnebog</translation> </message> <message> <source>Expert</source> - <translation type="unfinished"/> + <translation>Ekspert</translation> </message> <message> <source>Enable coin &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>&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> - <translation>Ã…bn Bitcoin-klientens port pÃ¥ routeren automatisk. Dette virker kun, nÃ¥r din router understøtter UPnP og UPnP er aktiveret.</translation> + <translation>Ã…bn automatisk Bitcoin-klientens port pÃ¥ routeren. Dette virker kun, nÃ¥r din router understøtter UPnP, og UPnP er aktiveret.</translation> </message> <message> <source>Map port using &UPnP</source> - <translation>Konfigurer port vha. UPnP</translation> + <translation>Konfigurér port vha. UPnP</translation> </message> <message> <source>Proxy &IP:</source> @@ -1105,7 +1113,7 @@ Adresse: %4 </message> <message> <source>Port of the proxy (e.g. 9050)</source> - <translation>Porten pÃ¥ proxyen (f.eks. 9050)</translation> + <translation>Port for proxyen (fx 9050)</translation> </message> <message> <source>SOCKS &Version:</source> @@ -1113,7 +1121,7 @@ Adresse: %4 </message> <message> <source>SOCKS version of the proxy (e.g. 5)</source> - <translation>SOCKS-version af proxyen (f.eks. 5)</translation> + <translation>SOCKS-version for proxyen (fx 5)</translation> </message> <message> <source>&Window</source> @@ -1125,15 +1133,15 @@ Adresse: %4 </message> <message> <source>&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&inimize on close</source> - <translation>Minimer ved lukning</translation> + <translation>Minimér ved lukning</translation> </message> <message> <source>&Display</source> @@ -1141,11 +1149,11 @@ Adresse: %4 </message> <message> <source>User Interface &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>&Unit to show amounts in:</source> @@ -1153,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> @@ -1165,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>&OK</source> @@ -1173,7 +1181,7 @@ Adresse: %4 </message> <message> <source>&Cancel</source> - <translation>Annuller</translation> + <translation>Annullér</translation> </message> <message> <source>default</source> @@ -1181,7 +1189,7 @@ Adresse: %4 </message> <message> <source>none</source> - <translation type="unfinished"/> + <translation>ingeningen</translation> </message> <message> <source>Confirm options reset</source> @@ -1189,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> @@ -1220,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> @@ -1228,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> @@ -1271,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> @@ -1283,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'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> @@ -1311,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> @@ -1338,34 +1346,34 @@ Adresse: %4 </message> <message> <source>Error: Specified data directory "%1" does not exist.</source> - <translation type="unfinished"/> + <translation>Fejl: Angivet datamappe "%1" 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 did't yet exit safely...</source> - <translation type="unfinished"/> + <source>Bitcoin Core didn't yet exit safely...</source> + <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>&Save Image...</source> - <translation>&Gem foto...</translation> + <translation>Gem billede …</translation> </message> <message> <source>&Copy Image</source> - <translation>&Kopiér foto</translation> + <translation>Kopiér foto</translation> </message> <message> <source>Save QR Code</source> @@ -1373,7 +1381,7 @@ Adresse: %4 </message> <message> <source>PNG Image (*.png)</source> - <translation type="unfinished"/> + <translation>PNG-billede (*.png)</translation> </message> </context> <context> @@ -1396,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> @@ -1408,7 +1416,7 @@ Adresse: %4 </message> <message> <source>Startup time</source> - <translation>Opstartstid</translation> + <translation>Opstartstidspunkt</translation> </message> <message> <source>Network</source> @@ -1448,23 +1456,23 @@ Adresse: %4 </message> <message> <source>&Network Traffic</source> - <translation type="unfinished"/> + <translation>Netværkstrafik</translation> </message> <message> <source>&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> @@ -1476,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> @@ -1484,11 +1492,11 @@ Adresse: %4 </message> <message> <source>Welcome to the Bitcoin RPC console.</source> - <translation>Velkommen til Bitcoin RPC-konsollen</translation> + <translation>Velkommen til Bitcoin RPC-konsollen.</translation> </message> <message> <source>Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.</source> - <translation>Brug op og ned-piletasterne til at navigere historikken og <b>Ctrl-L</b> til at rydde skærmen.</translation> + <translation>Brug op- og ned-piletasterne til at navigere i historikken og <b>Ctrl-L</b> til at rydde skærmen.</translation> </message> <message> <source>Type <b>help</b> for an overview of available commands.</source> @@ -1527,7 +1535,7 @@ Adresse: %4 <name>ReceiveCoinsDialog</name> <message> <source>&Amount:</source> - <translation>&Mængde:</translation> + <translation>Beløb:</translation> </message> <message> <source>&Label:</source> @@ -1535,35 +1543,35 @@ Adresse: %4 </message> <message> <source>&Message:</source> - <translation>&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&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 <b>optional</b>.</source> - <translation type="unfinished"/> + <translation>Brug denne formular for at anmode om betalinger. Alle felter er <b>valgfri</b>.</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> @@ -1571,35 +1579,35 @@ Adresse: %4 </message> <message> <source>Requested payments history</source> - <translation type="unfinished"/> + <translation>Historik over betalingsanmodninger</translation> </message> <message> <source>&Request payment</source> - <translation>&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> @@ -1610,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 &URI</source> - <translation>Kopiér &URL</translation> + <translation>Kopiér URI</translation> </message> <message> <source>Copy &Address</source> - <translation>Kopiér &Adresse</translation> + <translation>Kopiér adresse</translation> </message> <message> <source>&Save Image...</source> - <translation>&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> @@ -1658,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> @@ -1685,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> @@ -1700,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> @@ -1728,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> @@ -1764,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 &All</source> @@ -1788,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> @@ -1800,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> @@ -1844,23 +1852,23 @@ Adresse: %4 </message> <message> <source>The total exceeds your balance when the %1 transaction fee is included.</source> - <translation>Totalen overstiger din saldo, nÃ¥r %1 transaktionsgebyr er inkluderet.</translation> + <translation>Totalen overstiger din saldo, nÃ¥r transaktionsgebyret pÃ¥ %1 er inkluderet.</translation> </message> <message> <source>Duplicate address found, can only send to each address once per send operation.</source> - <translation>Duplikeret adresse fundet. Du kan kun sende til hver adresse en gang pr. afsendelse.</translation> + <translation>Duplikeret adresse fundet. Du kan kun sende til hver adresse én gang pr. afsendelse.</translation> </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> @@ -1868,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> @@ -1880,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> @@ -1899,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> @@ -1911,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> @@ -1931,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> @@ -1939,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 "bitcon:"-URI'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> @@ -1989,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> @@ -2009,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> @@ -2017,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> @@ -2041,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> @@ -2061,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 "Sign Message" to generate signature</source> @@ -2073,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> @@ -2109,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> @@ -2124,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> @@ -2146,7 +2154,7 @@ Adresse: %4 </message> <message> <source>conflicted</source> - <translation type="unfinished"/> + <translation>konflikt</translation> </message> <message> <source>%1/offline</source> @@ -2166,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> @@ -2202,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> @@ -2230,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 "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> - <translation type="unfinished"/> + <translation>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 "ikke accepteret", 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> @@ -2308,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> @@ -2332,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> @@ -2388,7 +2396,7 @@ Adresse: %4 </message> <message> <source>Amount removed from or added to balance.</source> - <translation>Beløb fjernet eller tilføjet balance.</translation> + <translation>Beløb trukket fra eller tilføjet balance.</translation> </message> </context> <context> @@ -2419,7 +2427,7 @@ Adresse: %4 </message> <message> <source>Range...</source> - <translation>Interval...</translation> + <translation>Interval …</translation> </message> <message> <source>Received with</source> @@ -2451,23 +2459,23 @@ Adresse: %4 </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>Edit label</source> - <translation>Rediger mærkat</translation> + <translation>Redigér mærkat</translation> </message> <message> <source>Show transaction details</source> @@ -2475,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> @@ -2538,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> @@ -2552,7 +2560,7 @@ Adresse: %4 <name>WalletView</name> <message> <source>&Export</source> - <translation>Eksporter</translation> + <translation>Eksportér</translation> </message> <message> <source>Export the data in the current tab to a file</source> @@ -2560,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> @@ -2568,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> @@ -2611,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 <port> (default: 8333 or testnet: 18333)</source> @@ -2623,7 +2631,7 @@ Adresse: %4 </message> <message> <source>Connect to a node to retrieve peer addresses, and disconnect</source> - <translation>Forbind til en knude for at modtage adresse, og afbryd</translation> + <translation>Forbind til en knude for at modtage adresser pÃ¥ andre knuder, og afbryd derefter</translation> </message> <message> <source>Specify your own public address</source> @@ -2647,15 +2655,15 @@ Adresse: %4 </message> <message> <source>Accept command line and JSON-RPC commands</source> - <translation>Accepter kommandolinje- og JSON-RPC-kommandoer</translation> + <translation>Acceptér kommandolinje- og JSON-RPC-kommandoer</translation> </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> - <translation>Kør i baggrunden som en service, og accepter kommandoer</translation> + <translation>Kør i baggrunden som en service, og acceptér kommandoer</translation> </message> <message> <source>Use the test network</source> @@ -2663,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: @@ -2686,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 "Bitcoin Alert" admin@foo.com +fx: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2703,19 +2711,19 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com </message> <message> <source>Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:15)</source> - <translation type="unfinished"/> + <translation>Rate-begræns kontinuerligt frie transaktioner til <n>*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> @@ -2723,7 +2731,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2731,27 +2739,27 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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 <n> megabytes (default: 100)</source> - <translation type="unfinished"/> + <translation>Flyt databaseaktivitet fra hukommelsespulje til disklog hver <n> 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, <0 = leave that many cores free, default: %d)</source> - <translation type="unfinished"/> + <translation>Sæt antallet af scriptverificeringstrÃ¥de (%u til %d, 0 = auto, <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> @@ -2759,11 +2767,11 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2775,11 +2783,11 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2787,19 +2795,19 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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><category> can be:</source> - <translation type="unfinished"/> + <translation><kategori> kan være:</translation> </message> <message> <source>Attempt to recover private keys from a corrupt wallet.dat</source> @@ -2807,7 +2815,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2815,7 +2823,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2823,15 +2831,15 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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 <port> (default: 8332 or testnet: 18332)</source> - <translation type="unfinished"/> + <translation>Forbind til JSON-RPC pÃ¥ <port> (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> @@ -2839,11 +2847,11 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2851,7 +2859,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2931,43 +2939,43 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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 <category> is not supplied, output all debugging information.</source> - <translation type="unfinished"/> + <translation>Hvis <kategori> 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: '%s'</source> - <translation type="unfinished"/> + <translation>Ugyldig -onion adresse: "%s"</translation> </message> <message> <source>Not enough file descriptors available.</source> @@ -2975,11 +2983,11 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2987,15 +2995,15 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3003,47 +3011,47 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3051,19 +3059,19 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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 <category> is optional)</source> - <translation type="unfinished"/> + <translation>Udskriv fejlsøgningsinformation (standard: 0, angivelse af <kategori> 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> @@ -3071,19 +3079,19 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com </message> <message> <source>Invalid amount for -minrelaytxfee=<amount>: '%s'</source> - <translation>Ugyldigt beløb til -minrelaytxfee=<beløb>:'%s'</translation> + <translation>Ugyldigt beløb til -minrelaytxfee=<beløb>: "%s"</translation> </message> <message> <source>Invalid amount for -mintxfee=<amount>: '%s'</source> - <translation>Ugyldigt beløb til -mintxfee=<beløb>:'%s'</translation> + <translation>Ugyldigt beløb til -mintxfee=<beløb>: "%s"</translation> </message> <message> <source>Limit size of signature cache to <n> entries (default: 50000)</source> - <translation type="unfinished"/> + <translation>Begræns størrelsen pÃ¥ signaturcache til <n> 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> @@ -3091,15 +3099,15 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com </message> <message> <source>Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)</source> - <translation>Maksimum for modtagelsesbuffer pr. forbindelse, <n>*1000 bytes (standard: 5000)</translation> + <translation>Maksimum for modtagelsesbuffer pr. forbindelse, <n>*1000 byte (standard: 5000)</translation> </message> <message> <source>Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)</source> - <translation>Maksimum for afsendelsesbuffer pr. forbindelse, <n>*1000 bytes (standard: 1000)</translation> + <translation>Maksimum for afsendelsesbuffer pr. forbindelse, <n>*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 <net> (IPv4, IPv6 or Tor)</source> @@ -3107,31 +3115,31 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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 <n> network messages</source> - <translation type="unfinished"/> + <translation>Drop tilfældigt 1 ud af hver <n> netværksbeskeder</translation> </message> <message> <source>Randomly fuzz 1 of every <n> network messages</source> - <translation type="unfinished"/> + <translation>Slør tilfældigt 1 ud af hver <n> 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> @@ -3139,7 +3147,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3147,19 +3155,19 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3175,7 +3183,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3195,11 +3203,11 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3215,11 +3223,11 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3283,7 +3291,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com </message> <message> <source>Loading addresses...</source> - <translation>Indlæser adresser...</translation> + <translation>Indlæser adresser …</translation> </message> <message> <source>Error loading wallet.dat: Wallet corrupted</source> @@ -3303,11 +3311,11 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com </message> <message> <source>Invalid -proxy address: '%s'</source> - <translation>Ugyldig -proxy adresse: '%s'</translation> + <translation>Ugyldig -proxy adresse: "%s"</translation> </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> - <translation>Ukendt netværk anført i -onlynet: '%s'</translation> + <translation>Ukendt netværk anført i -onlynet: "%s"</translation> </message> <message> <source>Unknown -socks proxy version requested: %i</source> @@ -3315,15 +3323,15 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com </message> <message> <source>Cannot resolve -bind address: '%s'</source> - <translation>Kan ikke finde -bind adressen: '%s'</translation> + <translation>Kan ikke finde -bind adressen: "%s"</translation> </message> <message> <source>Cannot resolve -externalip address: '%s'</source> - <translation>Kan ikke finde -externalip adressen: '%s'</translation> + <translation>Kan ikke finde -externalip adressen: "%s"</translation> </message> <message> <source>Invalid amount for -paytxfee=<amount>: '%s'</source> - <translation>Ugyldigt beløb for -paytxfee=<amount>: '%s'</translation> + <translation>Ugyldigt beløb for -paytxfee=<beløb>: "%s"</translation> </message> <message> <source>Invalid amount</source> @@ -3335,7 +3343,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com </message> <message> <source>Loading block index...</source> - <translation>Indlæser blokindeks...</translation> + <translation>Indlæser blokindeks …</translation> </message> <message> <source>Add a node to connect to and attempt to keep the connection open</source> @@ -3343,7 +3351,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com </message> <message> <source>Loading wallet...</source> - <translation>Indlæser tegnebog...</translation> + <translation>Indlæser tegnebog …</translation> </message> <message> <source>Cannot downgrade wallet</source> @@ -3355,7 +3363,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com </message> <message> <source>Rescanning...</source> - <translation>Genindlæser...</translation> + <translation>Genindlæser …</translation> </message> <message> <source>Done loading</source> @@ -3373,7 +3381,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com <source>You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions.</source> - <translation>Du skal angive rpcpassword=<password> i konfigurationsfilen: + <translation>Du skal angive rpcpassword=<adgangskode> 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_de.ts b/src/qt/locale/bitcoin_de.ts index 7f7e505e1d..888b48c251 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="de" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="de" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1047,6 +1047,14 @@ Adresse: %4</translation> <translation>IP-Adresse des Proxies (z.B. 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>Externe URLs (z.B. ein Block-Explorer), die im Kontextmenü des Transaktionsverlaufs eingefügt werden. In der URL wird %s durch den Transaktionshash ersetzt. Bei Angabe mehrerer URLs müssen diese durch "|" voneinander getrennt werden.</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>Externe Transaktions-URLs</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Aktive Kommandozeilenoptionen, die obige Konfiguration überschreiben:</translation> </message> @@ -1348,7 +1356,7 @@ Adresse: %4</translation> <translation>Fehler: Ungültige Kombination von -regtest und -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation>Bitcoin Core wurde noch nicht sicher beendet...</translation> </message> <message> diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index d13b974b8c..e957a0088e 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -1,13 +1,13 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="el_GR" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="el_GR" version="2.1"> <context> <name>AboutDialog</name> <message> <source>About Bitcoin Core</source> - <translation type="unfinished"/> + <translation>Σχετικά με το Bitcoin Core</translation> </message> <message> <source><b>Bitcoin Core</b> version</source> - <translation type="unfinished"/> + <translation><b>Bitcoin Core</b> Îκδοση</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>&About Bitcoin Core</source> - <translation type="unfinished"/> + <translation>&Σχετικά με το 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 &verification threads</source> @@ -1049,6 +1050,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1074,7 +1083,7 @@ Address: %4 </message> <message> <source>Expert</source> - <translation type="unfinished"/> + <translation>ΈμπειÏος</translation> </message> <message> <source>Enable coin &control features</source> @@ -1182,7 +1191,7 @@ Address: %4 </message> <message> <source>none</source> - <translation type="unfinished"/> + <translation>κανÎνα</translation> </message> <message> <source>Confirm options reset</source> @@ -1190,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> @@ -1221,7 +1230,7 @@ Address: %4 </message> <message> <source>Available:</source> - <translation type="unfinished"/> + <translation>ΔιαθÎσιμο:</translation> </message> <message> <source>Your current spendable balance</source> @@ -1350,7 +1359,7 @@ Address: %4 <translation>Σφάλμα: ΆκυÏος συνδυασμός των -regtest και -testnet</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> @@ -1362,11 +1371,11 @@ Address: %4 <name>QRImageWidget</name> <message> <source>&Save Image...</source> - <translation type="unfinished"/> + <translation>&Αποθήκευση εικόνας...</translation> </message> <message> <source>&Copy Image</source> - <translation type="unfinished"/> + <translation>&ΑντιγÏαφή εικόνας</translation> </message> <message> <source>Save QR Code</source> @@ -1401,7 +1410,7 @@ Address: %4 </message> <message> <source>General</source> - <translation type="unfinished"/> + <translation>Γενικά</translation> </message> <message> <source>Using OpenSSL version</source> @@ -1417,7 +1426,7 @@ Address: %4 </message> <message> <source>Name</source> - <translation type="unfinished"/> + <translation>Όνομα</translation> </message> <message> <source>Number of connections</source> @@ -1449,11 +1458,11 @@ Address: %4 </message> <message> <source>&Network Traffic</source> - <translation type="unfinished"/> + <translation>&Κίνηση δικτÏου</translation> </message> <message> <source>&Clear</source> - <translation type="unfinished"/> + <translation>&ΕκκαθάÏιση</translation> </message> <message> <source>Totals</source> @@ -1528,7 +1537,7 @@ Address: %4 <name>ReceiveCoinsDialog</name> <message> <source>&Amount:</source> - <translation type="unfinished"/> + <translation>&Ποσό:</translation> </message> <message> <source>&Label:</source> @@ -1536,7 +1545,7 @@ Address: %4 </message> <message> <source>&Message:</source> - <translation type="unfinished"/> + <translation>&Μήνυμα:</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> @@ -1576,7 +1585,7 @@ Address: %4 </message> <message> <source>&Request payment</source> - <translation type="unfinished"/> + <translation>&Αίτηση πληÏωμής</translation> </message> <message> <source>Show the selected request (does the same as double clicking an entry)</source> @@ -1600,7 +1609,7 @@ Address: %4 </message> <message> <source>Copy message</source> - <translation type="unfinished"/> + <translation>ΑντιγÏαφή μηνÏματος</translation> </message> <message> <source>Copy amount</source> @@ -1623,7 +1632,7 @@ Address: %4 </message> <message> <source>&Save Image...</source> - <translation type="unfinished"/> + <translation>&Αποθήκευση εικόνας...</translation> </message> <message> <source>Request payment to %1</source> @@ -1690,7 +1699,7 @@ Address: %4 </message> <message> <source>(no amount)</source> - <translation type="unfinished"/> + <translation>(κανÎνα ποσό)</translation> </message> </context> <context> @@ -1709,7 +1718,7 @@ Address: %4 </message> <message> <source>automatically selected</source> - <translation type="unfinished"/> + <translation>επιλεγμÎνο αυτόματα</translation> </message> <message> <source>Insufficient funds!</source> @@ -1745,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> @@ -1793,7 +1802,7 @@ Address: %4 </message> <message> <source>Copy quantity</source> - <translation type="unfinished"/> + <translation>ΑντιγÏαφή ποσότητας</translation> </message> <message> <source>Copy amount</source> @@ -1809,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> @@ -1821,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> @@ -1932,7 +1941,7 @@ Address: %4 </message> <message> <source>Remove this entry</source> - <translation type="unfinished"/> + <translation>ΑφαίÏεση αυτής της καταχώÏησης</translation> </message> <message> <source>Message:</source> @@ -1967,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> @@ -2125,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> @@ -2333,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> @@ -2476,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> @@ -2539,7 +2548,7 @@ Address: %4 <name>WalletFrame</name> <message> <source>No wallet has been loaded.</source> - <translation type="unfinished"/> + <translation>Δεν Îχει φοÏτωθεί ποÏτοφόλι</translation> </message> </context> <context> @@ -2577,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> @@ -2793,11 +2802,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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><category> can be:</source> @@ -2833,7 +2842,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Connection options:</source> - <translation type="unfinished"/> + <translation>ΕπιλογÎÏ‚ σÏνδεσης:</translation> </message> <message> <source>Corrupted block database detected</source> @@ -3037,7 +3046,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3221,7 +3230,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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_eo.ts b/src/qt/locale/bitcoin_eo.ts index 7f5dc3de2f..8c2869abac 100644 --- a/src/qt/locale/bitcoin_eo.ts +++ b/src/qt/locale/bitcoin_eo.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="eo" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="eo" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1048,6 +1048,14 @@ Adreso: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1349,7 +1357,7 @@ Adreso: %4 <translation>Eraro: nevalida kunigo de -regtest kaj -testnet</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index 0bd60be101..1ed40a77c2 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="es" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="es" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -320,7 +320,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.</t </message> <message> <source>&Backup Wallet...</source> - <translation>%Guardar copia del monedero...</translation> + <translation>&Guardar copia del monedero...</translation> </message> <message> <source>&Change Passphrase...</source> @@ -1051,6 +1051,14 @@ Dirección: %4 <translation>Dirección IP del proxy (p. ej. 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>URLs de terceros (por ejemplo, un explorador de bloques) que aparecen en la pestaña de transacciones como items del menú contextual. El %s en la URL es reemplazado por el hash de la transacción. Se pueden separar múltiples URLs por una barra vertical |.</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>URLs de transacciones de terceros</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Opciones activas de consola de comandos que tienen preferencia sobre las opciones antes mencionadas:</translation> </message> @@ -1352,8 +1360,8 @@ Dirección: %4 <translation>Error: Combinación no válida de -regtest y -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> - <translation type="unfinished"/> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>Bitcoin core no se ha cerrado de forma segura todavÃa...</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -1969,8 +1977,7 @@ Dirección: %4 <name>ShutdownWindow</name> <message> <source>Bitcoin Core is shutting down...</source> - <translation>Bitcoin Core se está cerrando... -</translation> + <translation>Bitcoin Core se está cerrando...</translation> </message> <message> <source>Do not shut down the computer until this window disappears.</source> @@ -2971,7 +2978,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Importing...</source> - <translation type="unfinished"/> + <translation>Importando...</translation> </message> <message> <source>Incorrect or no genesis block found. Wrong datadir for network?</source> diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts index b63743e5d6..758a190f75 100644 --- a/src/qt/locale/bitcoin_es_CL.ts +++ b/src/qt/locale/bitcoin_es_CL.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="es_CL" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="es_CL" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1051,6 +1051,14 @@ Dirección: %4</translation> <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1352,7 +1360,7 @@ Dirección: %4</translation> <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_es_DO.ts b/src/qt/locale/bitcoin_es_DO.ts index 6fca831017..6944c3157f 100644 --- a/src/qt/locale/bitcoin_es_DO.ts +++ b/src/qt/locale/bitcoin_es_DO.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="es_DO" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="es_DO" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1051,6 +1051,14 @@ Dirección: %4 <translation>Dirección IP del proxy (ej. 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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1352,7 +1360,7 @@ Dirección: %4 <translation>Error: Combinación no válida de -regtest y -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_es_MX.ts b/src/qt/locale/bitcoin_es_MX.ts index 6920f2300b..9a39551d6b 100644 --- a/src/qt/locale/bitcoin_es_MX.ts +++ b/src/qt/locale/bitcoin_es_MX.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="es_MX" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="es_MX" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Activar las opciones de linea de comando que sobre escriben las siguientes opciones:</translation> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_es_UY.ts b/src/qt/locale/bitcoin_es_UY.ts index d94ad1c938..03ecce46c0 100644 --- a/src/qt/locale/bitcoin_es_UY.ts +++ b/src/qt/locale/bitcoin_es_UY.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="es_UY" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="es_UY" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts index 8affc8a5d2..e6c27bf21c 100644 --- a/src/qt/locale/bitcoin_et.ts +++ b/src/qt/locale/bitcoin_et.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="et" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="et" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1047,6 +1047,14 @@ Aadress: %4âŽ</translation> <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1348,7 +1356,7 @@ Aadress: %4âŽ</translation> <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_eu_ES.ts b/src/qt/locale/bitcoin_eu_ES.ts index afa4d6c540..1fce25d6da 100644 --- a/src/qt/locale/bitcoin_eu_ES.ts +++ b/src/qt/locale/bitcoin_eu_ES.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="eu_ES" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="eu_ES" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index 805c7bb856..0dfbafb811 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="fa" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="fa" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1043,6 +1043,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1344,7 +1352,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts index 18a0dca224..3b82ffa5e5 100644 --- a/src/qt/locale/bitcoin_fa_IR.ts +++ b/src/qt/locale/bitcoin_fa_IR.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="fa_IR" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="fa_IR" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1042,6 +1042,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1343,7 +1351,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index 942dad5411..dc72359590 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="fi" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="fi" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1048,6 +1048,14 @@ Osoite: %4</translation> <translation>IP osoite proxille (esim. 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>Ulkopuoliset URL-osoitteet (esim. block explorer,) jotka esiintyvät siirrot-välilehdellä valikossa. %s URL-osoitteessa korvataan siirtotunnuksella. Useampi URL-osoite on eroteltu pystyviivalla |.</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>Kolmannen osapuolen rahansiirto URL:t</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Aktiiviset komentorivivalinnat jotka ohittavat ylläolevat valinnat:</translation> </message> @@ -1349,8 +1357,8 @@ Osoite: %4</translation> <translation>Virhe: Virheellinen yhdistelmä -regtest ja -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> - <translation>Bitcoin Core ei vielä sulkeutunut turvallisesti...</translation> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>Bitcoin Core ei ole vielä sulkeutunut turvallisesti...</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index e0d5bbdbcd..05089f0416 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="fr" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="fr" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1048,6 +1048,14 @@ Adresse : %4 <translation>Adresse IP du mandataire (par ex. 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>URL de tiers (par ex. un explorateur de blocs) apparaissant dans l'onglet des transactions comme éléments du menu contextuel. %s dans l'URL est remplacé par le hachage de la transaction. Les URL multiples sont séparées par une barre verticale |.</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>URL de transaction d'un tiers</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Options actives de ligne de commande qui annulent les options ci-dessus :</translation> </message> @@ -1349,8 +1357,8 @@ Adresse : %4 <translation>Erreur : combinaison invalide de -regtest et de -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> - <translation>Bitcoin Core ne s’est pas arrêté correctement...</translation> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>Bitcoin Core ne s'est pas encore arrêté en toute sécurité...</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> diff --git a/src/qt/locale/bitcoin_fr_CA.ts b/src/qt/locale/bitcoin_fr_CA.ts index 0df3eb3edd..ff22c2fd1c 100644 --- a/src/qt/locale/bitcoin_fr_CA.ts +++ b/src/qt/locale/bitcoin_fr_CA.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="fr_CA" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="fr_CA" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1044,6 +1044,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1345,7 +1353,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_gl.ts b/src/qt/locale/bitcoin_gl.ts index a1ee3545bf..ecf1fa2222 100644 --- a/src/qt/locale/bitcoin_gl.ts +++ b/src/qt/locale/bitcoin_gl.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="gl" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="gl" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1048,6 +1048,14 @@ Dirección: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1349,7 +1357,7 @@ Dirección: %4 <translation>Erro: combinación inválida de -regtest e -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_gu_IN.ts b/src/qt/locale/bitcoin_gu_IN.ts index 66b341545e..ed4a9265e4 100644 --- a/src/qt/locale/bitcoin_gu_IN.ts +++ b/src/qt/locale/bitcoin_gu_IN.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="gu_IN" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="gu_IN" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index 73378535a7..ae13df4524 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="he" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="he" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1047,6 +1047,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1348,7 +1356,7 @@ Address: %4 <translation>שגי××”: שילוב בלתי חוקי של regtest- ו testnet-.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_hi_IN.ts b/src/qt/locale/bitcoin_hi_IN.ts index d27e26b871..3ccac8899e 100644 --- a/src/qt/locale/bitcoin_hi_IN.ts +++ b/src/qt/locale/bitcoin_hi_IN.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="hi_IN" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="hi_IN" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1043,6 +1043,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1344,7 +1352,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts index b5f1595515..bd2b773d2f 100644 --- a/src/qt/locale/bitcoin_hr.ts +++ b/src/qt/locale/bitcoin_hr.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="hr" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="hr" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1043,6 +1043,14 @@ Adresa:%4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1196,7 +1204,7 @@ Adresa:%4 </message> <message> <source>The supplied proxy address is invalid.</source> - <translation type="unfinished"/> + <translation>Priložena proxy adresa je nevažeća.</translation> </message> </context> <context> @@ -1207,7 +1215,7 @@ Adresa:%4 </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> - <translation type="unfinished"/> + <translation>Prikazani podatci mogu biti zastarjeli. VaÅ¡ novÄanik se automatski sinkronizira s Bitcoin mrežom kada je veza uspostavljena, ali taj proces joÅ¡ nije zavrÅ¡en.</translation> </message> <message> <source>Wallet</source> @@ -1344,7 +1352,7 @@ Adresa:%4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> @@ -1483,7 +1491,7 @@ Adresa:%4 </message> <message> <source>Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.</source> - <translation type="unfinished"/> + <translation>Kako bi navigirali kroz povijest koristite strelice gore i dolje. <b>Ctrl-L</b> kako bi oÄistili ekran.</translation> </message> <message> <source>Type <b>help</b> for an overview of available commands.</source> @@ -2466,7 +2474,7 @@ Adresa:%4 </message> <message> <source>Show transaction details</source> - <translation type="unfinished"/> + <translation>Prikaži detalje transakcije</translation> </message> <message> <source>Export Transaction History</source> @@ -2622,7 +2630,7 @@ Adresa:%4 </message> <message> <source>Specify your own public address</source> - <translation type="unfinished"/> + <translation>Odaberi vlastitu javnu adresu</translation> </message> <message> <source>Threshold for disconnecting misbehaving peers (default: 100)</source> diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index de57490847..3d8d45a61d 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="hu" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="hu" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1048,6 +1048,14 @@ CÃm: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1349,7 +1357,7 @@ CÃm: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_id_ID.ts b/src/qt/locale/bitcoin_id_ID.ts index bd92878fed..2b9685f6a0 100644 --- a/src/qt/locale/bitcoin_id_ID.ts +++ b/src/qt/locale/bitcoin_id_ID.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="id_ID" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="id_ID" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -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>&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> @@ -1048,6 +1048,14 @@ Alamat: %4 <translation>Alamat IP proxy (cth. 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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>pilihan perintah-baris aktif menimpa atas pilihan-pilihan: </translation> </message> @@ -1342,14 +1350,14 @@ 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> <translation>Gagal: Gabungan -regtest dan -testnet salah</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> @@ -1400,7 +1408,7 @@ Alamat: %4 </message> <message> <source>General</source> - <translation type="unfinished"/> + <translation>Umum</translation> </message> <message> <source>Using OpenSSL version</source> @@ -1452,7 +1460,7 @@ Alamat: %4 </message> <message> <source>&Clear</source> - <translation type="unfinished"/> + <translation>&Kosongkan</translation> </message> <message> <source>Totals</source> @@ -1496,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> @@ -1543,7 +1551,7 @@ Alamat: %4 </message> <message> <source>R&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> @@ -1708,7 +1716,7 @@ Alamat: %4 </message> <message> <source>automatically selected</source> - <translation type="unfinished"/> + <translation>Pemilihan otomatis</translation> </message> <message> <source>Insufficient funds!</source> @@ -1939,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> @@ -1951,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> @@ -1997,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> @@ -2718,7 +2726,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2782,11 +2790,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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><category> can be:</source> @@ -2822,7 +2830,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Connection options:</source> - <translation type="unfinished"/> + <translation>Pilih koneksi:</translation> </message> <message> <source>Corrupted block database detected</source> @@ -2850,11 +2858,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2950,7 +2958,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2962,7 +2970,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2970,7 +2978,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2990,7 +2998,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3166,11 +3174,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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_it.ts b/src/qt/locale/bitcoin_it.ts index b9ef5e4d0b..cb9fed1ab9 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="it" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="it" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1049,6 +1049,15 @@ Indirizzo: %4 <translation>Indirizzo IP del proxy (es: 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>URL di terze parti (es: un block explorer) che appaiono nella tabella delle transazioni come voci nel menu contestuale. %s nell'URL è sostituito dall'hash della transazione. +Più URL vengono separati da una barra verticale |.</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>URL di transazione di terze parti</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Opzioni command-line attive che sostituiscono i settaggi sopra elencati:</translation> </message> @@ -1350,8 +1359,8 @@ Indirizzo: %4 <translation>Errore: combinazione di -regtest e -testnet non valida.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> - <translation>Bitcoin Core non è ancora stato chiuso in modo sicuro ...</translation> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>Bitcoin Core non si è ancora chiuso con sicurezza...</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index c7e4fe6091..d3a6cece87 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ja" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ja" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -7,7 +7,7 @@ </message> <message> <source><b>Bitcoin Core</b> version</source> - <translation type="unfinished"/> + <translation><b>ビットコインコア</b> ãƒãƒ¼ã‚¸ãƒ§ãƒ³</translation> </message> <message> <source> @@ -29,7 +29,7 @@ MIT/X11 ソフトウェア ライセンスã®ä¸‹ã§é…布ã•ã‚Œã¦ã„ã¾ã™ã€‚è© </message> <message> <source>The Bitcoin Core developers</source> - <translation type="unfinished"/> + <translation>ビットコインコアã®é–‹ç™ºè€…</translation> </message> <message> <source>(%1-bit)</source> @@ -128,7 +128,7 @@ MIT/X11 ソフトウェア ライセンスã®ä¸‹ã§é…布ã•ã‚Œã¦ã„ã¾ã™ã€‚è© </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> @@ -273,7 +273,7 @@ MIT/X11 ソフトウェア ライセンスã®ä¸‹ã§é…布ã•ã‚Œã¦ã„ã¾ã™ã€‚è© </message> <message> <source>Node</source> - <translation type="unfinished"/> + <translation>ノード</translation> </message> <message> <source>Show general overview of wallet</source> @@ -325,15 +325,15 @@ MIT/X11 ソフトウェア ライセンスã®ä¸‹ã§é…布ã•ã‚Œã¦ã„ã¾ã™ã€‚è© </message> <message> <source>&Sending addresses...</source> - <translation type="unfinished"/> + <translation>é€é‡‘先アドレス一覧 (&S)...</translation> </message> <message> <source>&Receiving addresses...</source> - <translation type="unfinished"/> + <translation>å—ã‘å–り用アドレス一覧 (&R)...</translation> </message> <message> <source>Open &URI...</source> - <translation type="unfinished"/> + <translation>URI ã‚’é–‹ã (&U)...</translation> </message> <message> <source>Importing blocks from disk...</source> @@ -437,7 +437,7 @@ MIT/X11 ソフトウェア ライセンスã®ä¸‹ã§é…布ã•ã‚Œã¦ã„ã¾ã™ã€‚è© </message> <message> <source>&About Bitcoin Core</source> - <translation type="unfinished"/> + <translation>ビットコインコアã«ã¤ã„㦠(&A)</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> @@ -453,7 +453,7 @@ MIT/X11 ソフトウェア ライセンスã®ä¸‹ã§é…布ã•ã‚Œã¦ã„ã¾ã™ã€‚è© </message> <message> <source>&Command-line options</source> - <translation type="unfinished"/> + <translation>コマンドラインオプション (&C)</translation> </message> <message> <source>Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options</source> @@ -493,11 +493,11 @@ MIT/X11 ソフトウェア ライセンスã®ä¸‹ã§é…布ã•ã‚Œã¦ã„ã¾ã™ã€‚è© </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></translation> + <translation><numerusform>%n å¹´</numerusform></translation> </message> <message> <source>%1 behind</source> @@ -579,11 +579,11 @@ Address: %4 </message> <message> <source>Quantity:</source> - <translation type="unfinished"/> + <translation>æ•°é‡:</translation> </message> <message> <source>Bytes:</source> - <translation type="unfinished"/> + <translation>ãƒã‚¤ãƒˆ:</translation> </message> <message> <source>Amount:</source> @@ -591,11 +591,11 @@ Address: %4 </message> <message> <source>Priority:</source> - <translation type="unfinished"/> + <translation>優先度:</translation> </message> <message> <source>Fee:</source> - <translation type="unfinished"/> + <translation>手数料:</translation> </message> <message> <source>Low Output:</source> @@ -603,7 +603,7 @@ Address: %4 </message> <message> <source>After Fee:</source> - <translation type="unfinished"/> + <translation>手数料差引後:</translation> </message> <message> <source>Change:</source> @@ -611,15 +611,15 @@ Address: %4 </message> <message> <source>(un)select all</source> - <translation type="unfinished"/> + <translation>ã™ã¹ã¦é¸æŠž/é¸æŠžè§£é™¤</translation> </message> <message> <source>Tree mode</source> - <translation type="unfinished"/> + <translation>ツリーモード</translation> </message> <message> <source>List mode</source> - <translation type="unfinished"/> + <translation>リストモード</translation> </message> <message> <source>Amount</source> @@ -635,7 +635,7 @@ Address: %4 </message> <message> <source>Confirmations</source> - <translation type="unfinished"/> + <translation>検証数</translation> </message> <message> <source>Confirmed</source> @@ -643,7 +643,7 @@ Address: %4 </message> <message> <source>Priority</source> - <translation type="unfinished"/> + <translation>優先度</translation> </message> <message> <source>Copy address</source> @@ -671,23 +671,23 @@ Address: %4 </message> <message> <source>Copy quantity</source> - <translation type="unfinished"/> + <translation>æ•°é‡ã‚’コピーã™ã‚‹</translation> </message> <message> <source>Copy fee</source> - <translation type="unfinished"/> + <translation>手数料をコピーã™ã‚‹</translation> </message> <message> <source>Copy after fee</source> - <translation type="unfinished"/> + <translation>手数料差引後ã®å€¤ã‚’コピーã™ã‚‹</translation> </message> <message> <source>Copy bytes</source> - <translation type="unfinished"/> + <translation>ãƒã‚¤ãƒˆæ•°ã‚’コピーã™ã‚‹</translation> </message> <message> <source>Copy priority</source> - <translation type="unfinished"/> + <translation>優先度をコピーã™ã‚‹</translation> </message> <message> <source>Copy low output</source> @@ -739,7 +739,7 @@ Address: %4 </message> <message> <source>none</source> - <translation type="unfinished"/> + <translation>ãªã—</translation> </message> <message> <source>Dust</source> @@ -771,7 +771,7 @@ Address: %4 </message> <message> <source>This label turns red, if the priority is smaller than "medium".</source> - <translation type="unfinished"/> + <translation>優先度ãŒã€Œä¸ã€æœªæº€ã®å ´åˆã«ã¯ã€ã“ã®ãƒ©ãƒ™ãƒ«ã¯èµ¤ããªã‚Šã¾ã™ã€‚</translation> </message> <message> <source>This label turns red, if any recipient receives an amount smaller than %1.</source> @@ -978,11 +978,11 @@ Address: %4 <name>OpenURIDialog</name> <message> <source>Open URI</source> - <translation type="unfinished"/> + <translation>URI ã‚’é–‹ã</translation> </message> <message> <source>Open payment request from URI or file</source> - <translation type="unfinished"/> + <translation>URI ã¾ãŸã¯ãƒ•ã‚¡ã‚¤ãƒ«ã‹ã‚‰æ”¯æ‰•ã„リクエストを開ã</translation> </message> <message> <source>URI:</source> @@ -990,11 +990,11 @@ Address: %4 </message> <message> <source>Select payment request file</source> - <translation type="unfinished"/> + <translation>支払ã„リクエストファイルをé¸æŠžã—ã¦ãã ã•ã„</translation> </message> <message> <source>Select payment request file to open</source> - <translation type="unfinished"/> + <translation>é–‹ããŸã„支払ã„リクエストファイルをé¸æŠžã—ã¦ãã ã•ã„</translation> </message> </context> <context> @@ -1025,11 +1025,11 @@ Address: %4 </message> <message> <source>Size of &database cache</source> - <translation type="unfinished"/> + <translation>データベースã‚ャッシュã®ã‚µã‚¤ã‚º (&D)</translation> </message> <message> <source>MB</source> - <translation type="unfinished"/> + <translation>MB</translation> </message> <message> <source>Number of script &verification threads</source> @@ -1045,6 +1045,14 @@ Address: %4 </message> <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <translation>プãƒã‚ã‚·ã®IPアドレス (例ãˆã° 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"/> + </message> + <message> + <source>Third party transaction URLs</source> <translation type="unfinished"/> </message> <message> @@ -1069,15 +1077,15 @@ Address: %4 </message> <message> <source>W&allet</source> - <translation type="unfinished"/> + <translation>ウォレット (&A)</translation> </message> <message> <source>Expert</source> - <translation type="unfinished"/> + <translation>エクスãƒãƒ¼ãƒˆ</translation> </message> <message> <source>Enable coin &control features</source> - <translation type="unfinished"/> + <translation>コインコントãƒãƒ¼ãƒ«æ©Ÿèƒ½ã‚’有効化ã™ã‚‹ (&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> @@ -1181,7 +1189,7 @@ Address: %4 </message> <message> <source>none</source> - <translation type="unfinished"/> + <translation>ãªã—</translation> </message> <message> <source>Confirm options reset</source> @@ -1350,7 +1358,7 @@ Address: %4 <translation>エラー: -regtestã¨-testnetã¯ä¸€ç·’ã«ã™ã‚‹ã®ã¯ç„¡åŠ¹ã§ã™ã€‚</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> @@ -1417,7 +1425,7 @@ Address: %4 </message> <message> <source>Name</source> - <translation type="unfinished"/> + <translation>åå‰</translation> </message> <message> <source>Number of connections</source> @@ -1461,11 +1469,11 @@ Address: %4 </message> <message> <source>In:</source> - <translation type="unfinished"/> + <translation>入力:</translation> </message> <message> <source>Out:</source> - <translation type="unfinished"/> + <translation>出力:</translation> </message> <message> <source>Build date</source> @@ -1497,31 +1505,31 @@ Address: %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 m</translation> </message> <message> <source>%1 h</source> - <translation type="unfinished"/> + <translation>%1 h</translation> </message> <message> <source>%1 h %2 m</source> - <translation type="unfinished"/> + <translation>%1 h %2 m</translation> </message> </context> <context> @@ -1536,7 +1544,7 @@ Address: %4 </message> <message> <source>&Message:</source> - <translation type="unfinished"/> + <translation>メッセージ (&M):</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> @@ -1600,7 +1608,7 @@ Address: %4 </message> <message> <source>Copy message</source> - <translation type="unfinished"/> + <translation>メッセージをコピーã™ã‚‹</translation> </message> <message> <source>Copy amount</source> @@ -1615,11 +1623,11 @@ Address: %4 </message> <message> <source>Copy &URI</source> - <translation type="unfinished"/> + <translation>URI をコピーã™ã‚‹ (&U)</translation> </message> <message> <source>Copy &Address</source> - <translation type="unfinished"/> + <translation>アドレスをコピーã™ã‚‹ (&A)</translation> </message> <message> <source>&Save Image...</source> @@ -1627,7 +1635,7 @@ Address: %4 </message> <message> <source>Request payment to %1</source> - <translation type="unfinished"/> + <translation>%1 ã¸ã®æ”¯æ‰•ã„リクエストを行ã†</translation> </message> <message> <source>Payment information</source> @@ -1635,7 +1643,7 @@ Address: %4 </message> <message> <source>URI</source> - <translation type="unfinished"/> + <translation>URI</translation> </message> <message> <source>Address</source> @@ -1701,27 +1709,27 @@ Address: %4 </message> <message> <source>Coin Control Features</source> - <translation type="unfinished"/> + <translation>コインコントãƒãƒ¼ãƒ«æ©Ÿèƒ½</translation> </message> <message> <source>Inputs...</source> - <translation type="unfinished"/> + <translation>入力...</translation> </message> <message> <source>automatically selected</source> - <translation type="unfinished"/> + <translation>自動é¸æŠž</translation> </message> <message> <source>Insufficient funds!</source> - <translation type="unfinished"/> + <translation>残高ä¸è¶³ã§ã™ï¼</translation> </message> <message> <source>Quantity:</source> - <translation type="unfinished"/> + <translation>æ•°é‡:</translation> </message> <message> <source>Bytes:</source> - <translation type="unfinished"/> + <translation>ãƒã‚¤ãƒˆ:</translation> </message> <message> <source>Amount:</source> @@ -1729,11 +1737,11 @@ Address: %4 </message> <message> <source>Priority:</source> - <translation type="unfinished"/> + <translation>優先度:</translation> </message> <message> <source>Fee:</source> - <translation type="unfinished"/> + <translation>手数料:</translation> </message> <message> <source>Low Output:</source> @@ -1741,7 +1749,7 @@ Address: %4 </message> <message> <source>After Fee:</source> - <translation type="unfinished"/> + <translation>手数料差引後:</translation> </message> <message> <source>Change:</source> @@ -1793,7 +1801,7 @@ Address: %4 </message> <message> <source>Copy quantity</source> - <translation type="unfinished"/> + <translation>æ•°é‡ã‚’コピーã™ã‚‹</translation> </message> <message> <source>Copy amount</source> @@ -1801,19 +1809,19 @@ Address: %4 </message> <message> <source>Copy fee</source> - <translation type="unfinished"/> + <translation>手数料をコピーã™ã‚‹</translation> </message> <message> <source>Copy after fee</source> - <translation type="unfinished"/> + <translation>手数料差引後ã®å€¤ã‚’コピーã™ã‚‹</translation> </message> <message> <source>Copy bytes</source> - <translation type="unfinished"/> + <translation>ãƒã‚¤ãƒˆæ•°ã‚’コピーã™ã‚‹</translation> </message> <message> <source>Copy priority</source> - <translation type="unfinished"/> + <translation>優先度をコピーã™ã‚‹</translation> </message> <message> <source>Copy low output</source> @@ -1956,7 +1964,7 @@ Address: %4 </message> <message> <source>Pay To:</source> - <translation type="unfinished"/> + <translation>支払先:</translation> </message> <message> <source>Memo:</source> @@ -2125,7 +2133,7 @@ Address: %4 </message> <message> <source>The Bitcoin Core developers</source> - <translation type="unfinished"/> + <translation>ビットコインコアã®é–‹ç™ºè€…</translation> </message> <message> <source>[testnet]</source> @@ -2136,7 +2144,7 @@ Address: %4 <name>TrafficGraphWidget</name> <message> <source>KB/s</source> - <translation type="unfinished"/> + <translation>KB/s</translation> </message> </context> <context> @@ -2333,11 +2341,11 @@ Address: %4 </message> <message> <source>Offline</source> - <translation type="unfinished"/> + <translation>オフライン</translation> </message> <message> <source>Unconfirmed</source> - <translation type="unfinished"/> + <translation>未検証</translation> </message> <message> <source>Confirming (%1 of %2 recommended confirmations)</source> @@ -2476,19 +2484,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>トランザクション履æ´ã‚’ %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> @@ -2652,7 +2660,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> @@ -2791,11 +2799,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><category> can be:</source> @@ -2823,7 +2831,7 @@ rpcpassword=%s </message> <message> <source>Connect through SOCKS proxy</source> - <translation type="unfinished"/> + <translation>SOCKS プãƒã‚シ経由ã§æŽ¥ç¶šã™ã‚‹</translation> </message> <message> <source>Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)</source> @@ -2840,7 +2848,7 @@ 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> @@ -2932,11 +2940,11 @@ rpcpassword=%s </message> <message> <source>Fee per kB to add to transactions you send</source> - <translation type="unfinished"/> + <translation>é€ä¿¡ã™ã‚‹ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã®1kBã‚ãŸã‚Šã®æ‰‹æ•°æ–™</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> @@ -2944,7 +2952,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> @@ -2956,7 +2964,7 @@ rpcpassword=%s </message> <message> <source>If <category> is not supplied, output all debugging information.</source> - <translation type="unfinished"/> + <translation><category> ãŒä¸Žãˆã‚‰ã‚Œãªã‹ã£ãŸå ´åˆã«ã¯ã€ã™ã¹ã¦ã®ãƒ‡ãƒãƒƒã‚°æƒ…å ±ãŒå‡ºåŠ›ã•ã‚Œã¾ã™ã€‚</translation> </message> <message> <source>Importing...</source> @@ -2980,7 +2988,7 @@ rpcpassword=%s </message> <message> <source>RPC client options:</source> - <translation type="unfinished"/> + <translation>RPC クライアントã®ã‚ªãƒ—ション:</translation> </message> <message> <source>Rebuild block chain index from current blk000??.dat files</source> @@ -3028,7 +3036,7 @@ rpcpassword=%s </message> <message> <source>Wait for RPC server to start</source> - <translation type="unfinished"/> + <translation>RPC サーãƒãŒé–‹å§‹ã™ã‚‹ã®ã‚’å¾…ã¤</translation> </message> <message> <source>Wallet %s resides outside data directory %s</source> @@ -3040,7 +3048,7 @@ rpcpassword=%s </message> <message> <source>Warning: Deprecated argument -debugnet ignored, use -debug=net</source> - <translation type="unfinished"/> + <translation>è¦å‘Š: éžæŽ¨å¥¨ã®å¼•æ•° -debugnet ã¯ç„¡è¦–ã•ã‚Œã¾ã—ãŸã€‚-debug=net を使用ã—ã¦ãã ã•ã„</translation> </message> <message> <source>You need to rebuild the database using -reindex to change -txindex</source> @@ -3080,11 +3088,11 @@ rpcpassword=%s </message> <message> <source>Limit size of signature cache to <n> entries (default: 50000)</source> - <translation type="unfinished"/> + <translation>ç½²åã‚ャッシュã®ã‚µã‚¤ã‚ºã‚’ <n> エントリーã«åˆ¶é™ã™ã‚‹ (デフォルト: 50000)</translation> </message> <message> <source>Log transaction priority and fee per kB when mining blocks (default: 0)</source> - <translation type="unfinished"/> + <translation>ブãƒãƒƒã‚¯ã®æŽ¡æŽ˜æ™‚ã«ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã®å„ªå…ˆåº¦ã¨1kBã‚ãŸã‚Šã®æ‰‹æ•°æ–™ã‚’ãƒã‚°ã«æ®‹ã™ (デフォルト: 0)</translation> </message> <message> <source>Maintain a full transaction index (default: 0)</source> @@ -3116,11 +3124,11 @@ rpcpassword=%s </message> <message> <source>RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source> - <translation type="unfinished"/> + <translation>RPC SSL オプション: (SSLã®ã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—æ‰‹é †ã¯ãƒ“ットコインWikiã‚’å‚ç…§ã—ã¦ãã ã•ã„)</translation> </message> <message> <source>RPC server options:</source> - <translation type="unfinished"/> + <translation>RPCサーãƒã®ã‚ªãƒ—ション:</translation> </message> <message> <source>Randomly drop 1 of every <n> network messages</source> diff --git a/src/qt/locale/bitcoin_ka.ts b/src/qt/locale/bitcoin_ka.ts index fd14152b04..fda2e97037 100644 --- a/src/qt/locale/bitcoin_ka.ts +++ b/src/qt/locale/bitcoin_ka.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ka" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ka" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1048,6 +1048,14 @@ Address: %4 <translation>პრáƒáƒ¥áƒ¡áƒ˜áƒ¡ IP-მისáƒáƒ›áƒáƒ თი (მáƒáƒ’.: 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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>სáƒáƒ™áƒáƒ›áƒáƒœáƒ“რსტრიქáƒáƒœáƒ˜áƒ¡ áƒáƒ¥áƒ¢áƒ˜áƒ£áƒ ი áƒáƒžáƒªáƒ˜áƒ”ბი, რáƒáƒ›áƒšáƒ”ბიც გáƒáƒ“áƒáƒ¤áƒáƒ áƒáƒ•áƒ”ნ ზემáƒáƒ—ნáƒáƒ©áƒ•áƒ”ნებს:</translation> </message> @@ -1349,7 +1357,7 @@ Address: %4 <translation>შეცდáƒáƒ›áƒ: -regtest-ისრდრ-testnet-ის დáƒáƒ£áƒ¨áƒ•áƒ”ბელი კáƒáƒ›áƒ‘ინáƒáƒªáƒ˜áƒ.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_kk_KZ.ts b/src/qt/locale/bitcoin_kk_KZ.ts index e35055ebd1..b913ba9858 100644 --- a/src/qt/locale/bitcoin_kk_KZ.ts +++ b/src/qt/locale/bitcoin_kk_KZ.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="kk_KZ" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="kk_KZ" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_ko_KR.ts b/src/qt/locale/bitcoin_ko_KR.ts index c1584600cf..ce30a8603d 100644 --- a/src/qt/locale/bitcoin_ko_KR.ts +++ b/src/qt/locale/bitcoin_ko_KR.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ko_KR" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ko_KR" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -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> @@ -48,7 +48,7 @@ MIT/X11 프로그램 ë¼ì´ì„ ìŠ¤ì— ë”°ë¼ ë°°í¬í•©ë‹ˆë‹¤. COPYING ë˜ëŠ” http </message> <message> <source>&New</source> - <translation type="unfinished"/> + <translation>새 í•ëª©(N)</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> @@ -60,7 +60,7 @@ MIT/X11 프로그램 ë¼ì´ì„ ìŠ¤ì— ë”°ë¼ ë°°í¬í•©ë‹ˆë‹¤. COPYING ë˜ëŠ” http </message> <message> <source>C&lose</source> - <translation type="unfinished"/> + <translation>닫기 (L)</translation> </message> <message> <source>&Copy Address</source> @@ -76,7 +76,7 @@ MIT/X11 프로그램 ë¼ì´ì„ ìŠ¤ì— ë”°ë¼ ë°°í¬í•©ë‹ˆë‹¤. COPYING ë˜ëŠ” http </message> <message> <source>&Export</source> - <translation type="unfinished"/> + <translation>&내보내기</translation> </message> <message> <source>&Delete</source> @@ -92,7 +92,7 @@ MIT/X11 프로그램 ë¼ì´ì„ ìŠ¤ì— ë”°ë¼ ë°°í¬í•©ë‹ˆë‹¤. COPYING ë˜ëŠ” http </message> <message> <source>C&hoose</source> - <translation type="unfinished"/> + <translation>ì„ íƒí•˜ê¸° (H)</translation> </message> <message> <source>Sending addresses</source> @@ -108,7 +108,7 @@ MIT/X11 프로그램 ë¼ì´ì„ ìŠ¤ì— ë”°ë¼ ë°°í¬í•©ë‹ˆë‹¤. COPYING ë˜ëŠ” http </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>비트코ì¸ì„ ë°›ì„ ìˆ˜ 있는 계좌 주소입니다. 매 거래마다 새로운 주소 ì‚¬ìš©ì„ ê¶Œìž¥í•©ë‹ˆë‹¤. </translation> </message> <message> <source>Copy &Label</source> @@ -401,11 +401,11 @@ MIT/X11 프로그램 ë¼ì´ì„ ìŠ¤ì— ë”°ë¼ ë°°í¬í•©ë‹ˆë‹¤. COPYING ë˜ëŠ” http </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation type="unfinished"/> + <translation>지갑 주소가 ìžì‹ ì†Œìœ ì˜ ê²ƒì¸ì§€ ì¦ëª…하기 위해 ë¹„íŠ¸ì½”ì¸ ì£¼ì†Œì— ì„œëª…í• ìˆ˜ 있습니다.</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation type="unfinished"/> + <translation>ë¹„íŠ¸ì½”ì¸ ì£¼ì†Œì˜ ì „ìž ì„œëª… 확ì¸ì„ 위해 ì²¨ë¶€ëœ ë©”ì‹œì§€ê°€ ìžˆì„ ê²½ìš° ì´ë¥¼ ê²€ì¦í• 수 있습니다.</translation> </message> <message> <source>&File</source> @@ -441,11 +441,11 @@ MIT/X11 프로그램 ë¼ì´ì„ ìŠ¤ì— ë”°ë¼ ë°°í¬í•©ë‹ˆë‹¤. COPYING ë˜ëŠ” http </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished"/> + <translation>한번 ì´ìƒ ì‚¬ìš©ëœ ë³´ë‚´ëŠ” 주소와 주소 ì œëª©ì˜ ëª©ë¡ì„ ë³´ì—¬ì¤ë‹ˆë‹¤.</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished"/> + <translation>한번 ì´ìƒ ì‚¬ìš©ëœ ë°›ëŠ” 주소와 주소 ì œëª©ì˜ ëª©ë¡ì„ ë³´ì—¬ì¤ë‹ˆë‹¤.</translation> </message> <message> <source>Open a bitcoin: URI or payment request</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 "medium".</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> @@ -814,7 +814,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> @@ -869,7 +869,7 @@ Address: %4 </message> <message> <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> - <translation type="unfinished"/> + <translation>í´ë”ê°€ ì´ë¯¸ 존재합니다. 새로운 í´ë” ìƒì„±ì„ ì›í•œë‹¤ë©´ %1 ëª…ë ¹ì–´ë¥¼ 추가하세요. </translation> </message> <message> <source>Path already exists, and is not a directory.</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 "%1" can not be created.</source> - <translation type="unfinished"/> + <translation>오류 : ë³„ë„ ì •ì˜í•œ í´ë”명 "%1" ìƒì„±ì— 실패했습니다. </translation> </message> <message> <source>Error</source> @@ -1033,7 +1033,7 @@ Address: %4 </message> <message> <source>Number of script &verification threads</source> - <translation type="unfinished"/> + <translation>스í¬ë¦½íŠ¸ ì¸ì¦ ì“°ë ˆë“œì˜ ê°œìˆ˜</translation> </message> <message> <source>Connect to the Bitcoin network through a SOCKS proxy.</source> @@ -1048,6 +1048,14 @@ Address: %4 <translation>프ë¡ì‹œ ì•„ì´í”¼ 주소(예. 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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>ì œ 3ìž ê±°ëž˜ URLs</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1073,11 +1081,11 @@ Address: %4 </message> <message> <source>Expert</source> - <translation type="unfinished"/> + <translation>ì „ë¬¸ê°€</translation> </message> <message> <source>Enable coin &control features</source> - <translation type="unfinished"/> + <translation>ì½”ì¸ ìƒì„¸ ì œì–´ê¸°ëŠ¥ì„ í™œì„±í™”í•©ë‹ˆë‹¤ - &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> @@ -1085,7 +1093,7 @@ Address: %4 </message> <message> <source>&Spend unconfirmed change</source> - <translation type="unfinished"/> + <translation>&확ì¸ë˜ì§€ ì•Šì€ ëˆì„ 쓰다</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> @@ -1165,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>&OK</source> @@ -1189,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> @@ -1197,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> @@ -1267,11 +1275,11 @@ Address: %4 </message> <message> <source>URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> - <translation type="unfinished"/> + <translation>URIì˜ íŒŒì‹±ì— ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ìž˜ëª»ëœ ë¹„íŠ¸ì½”ì¸ ì£¼ì†Œë‚˜ URI 파ë¼ë¯¸í„° êµ¬ì„±ì— ì˜¤ë¥˜ê°€ ì¡´ìž¬í• ìˆ˜ 있습니다.</translation> </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> @@ -1287,7 +1295,7 @@ Address: %4 </message> <message> <source>Your active proxy doesn'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> @@ -1295,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> @@ -1346,11 +1354,11 @@ 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 did't yet exit safely...</source> - <translation type="unfinished"/> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>ë¹„íŠ¸ì½”ì¸ ì½”ì–´ê°€ ì•„ì§ ì•ˆì „í•˜ê²Œ 종료ë˜ì§€ 않았습니다.</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -1452,7 +1460,7 @@ Address: %4 </message> <message> <source>&Clear</source> - <translation type="unfinished"/> + <translation>&지우기</translation> </message> <message> <source>Totals</source> @@ -1539,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&euse an existing receiving address (not recommended)</source> - <translation type="unfinished"/> + <translation>í˜„ìž¬ì˜ ìˆ˜ì·¨ìš© 주소를 재사용합니다만 권장하지는 않습니다. (R&)</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> @@ -1555,11 +1563,11 @@ Address: %4 </message> <message> <source>Use this form to request payments. All fields are <b>optional</b>.</source> - <translation type="unfinished"/> + <translation>ì§€ê¸‰ì„ ìš”ì²í•˜ê¸° 위해 아래 형ì‹ì„ 사용하세요. ìž…ë ¥ê°’ì€ <b>ì„ íƒ ì‚¬í•</b> 입니다.</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>ìš”ì²í• 금액 ìž…ë ¥ì¹¸ìœ¼ë¡œ ì„ íƒ ì‚¬í•ìž…니다. 빈 칸으로 ë‘거나 íŠ¹ì • ê¸ˆì•¡ì´ í•„ìš”í•˜ì§€ 않는 경우 0ì„ ìž…ë ¥í•˜ì„¸ìš”. </translation> </message> <message> <source>Clear all fields of the form.</source> @@ -1704,7 +1712,7 @@ Address: %4 </message> <message> <source>Inputs...</source> - <translation type="unfinished"/> + <translation>ìž…ë ¥...</translation> </message> <message> <source>automatically selected</source> @@ -1856,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> @@ -1899,7 +1907,7 @@ Address: %4 </message> <message> <source>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> - <translation type="unfinished"/> + <translation>비트코ì¸ì„ ì†¡ê¸ˆí• ì§€ê°‘ 주소 ìž…ë ¥í•˜ê¸° (예 : 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation> </message> <message> <source>Enter a label for this address to add it to your address book</source> @@ -1943,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> @@ -1955,7 +1963,7 @@ Address: %4 </message> <message> <source>Pay To:</source> - <translation type="unfinished"/> + <translation>ì†¡ê¸ˆí• ëŒ€ìƒ : </translation> </message> <message> <source>Memo:</source> @@ -2041,7 +2049,7 @@ Address: %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 type="unfinished"/> + <translation>메시지를 ê²€ì¦í•˜ê¸° 위해 아래 ì¹¸ì— ê°ê° 지갑 주소와 메시지, ì „ìžì„œëª…ì„ ìž…ë ¥í•˜ì„¸ìš”. (메시지 ì›ë³¸ì˜ ë„어쓰기, 들여쓰기, í–‰ 나눔 ë“±ì´ ì •í™•í•˜ê²Œ ìž…ë ¥ë˜ì–´ì•¼ 하므로 ì›ë³¸ì„ 복사해서 ìž…ë ¥í•˜ì„¸ìš”) ì´ ê¸°ëŠ¥ì€ ë©”ì‹œì§€ ê²€ì¦ì´ 주 목ì ì´ë©°, ë„¤íŠ¸ì›Œí¬ ì¹¨ìž…ìžì— ì˜í•´ 변조ë˜ì§€ ì•Šë„ë¡ ì „ìžì„œëª… í•´ë…ì— ë¶ˆí•„ìš”í•œ ì‹œê°„ì„ ì†Œëª¨í•˜ì§€ 마세요. </translation> </message> <message> <source>The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -2166,7 +2174,7 @@ Address: %4 </message> <message numerus="yes"> <source>, broadcast through %n node(s)</source> - <translation type="unfinished"><numerusform></numerusform></translation> + <translation><numerusform>%n 노드를 ê±°ì³ ì „íŒŒí•©ë‹ˆë‹¤.</numerusform></translation> </message> <message> <source>Date</source> @@ -2238,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 "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> - <translation type="unfinished"/> + <translation>ì‹ ê·œ ì±„êµ´ëœ ì½”ì¸ì´ 사용ë˜ê¸° 위해서는 %1 ê°œì˜ ë¸”ëŸì´ 경과ë˜ì–´ì•¼ 합니다. 블ëŸì„ ìƒì„±í• ë•Œ 블ëŸì²´ì¸ì— 추가ë˜ë„ë¡ ë„¤íŠ¸ì›Œí¬ì— ì „íŒŒë˜ëŠ” ê³¼ì •ì„ ê±°ì¹˜ëŠ”ë°, 블ëŸì²´ì¸ì— í¬í•¨ë˜ì§€ ëª»í•˜ê³ ì‹¤íŒ¨í•œë‹¤ë©´ 해당 블ëŸì˜ ìƒíƒœëŠ” '미승ì¸'으로 표현ë˜ê³ ë¹„íŠ¸ì½”ì¸ ë˜í•œ 사용ë 수 없습니다. ì´ í˜„ìƒì€ 다른 노드가 비슷한 ì‹œê°„ëŒ€ì— ë™ì‹œì— 블ëŸì„ ìƒì„±í• ë•Œ 종종 ë°œìƒí• 수 있습니다. </translation> </message> <message> <source>Debug information</source> @@ -2270,7 +2278,7 @@ Address: %4 </message> <message numerus="yes"> <source>Open for %n more block(s)</source> - <translation type="unfinished"><numerusform></numerusform></translation> + <translation><numerusform>%n ê°œì˜ ì¶”ê°€ 블ëŸì„ ì½ìŠµë‹ˆë‹¤.</numerusform></translation> </message> <message> <source>unknown</source> @@ -2308,11 +2316,11 @@ 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> - <translation type="unfinished"><numerusform></numerusform></translation> + <translation><numerusform>%n ê°œì˜ ì¶”ê°€ 블ëŸì„ ì½ìŠµë‹ˆë‹¤.</numerusform></translation> </message> <message> <source>Open until %1</source> @@ -2340,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> @@ -2552,7 +2560,7 @@ Address: %4 <name>WalletView</name> <message> <source>&Export</source> - <translation type="unfinished"/> + <translation>&내보내기</translation> </message> <message> <source>Export the data in the current tab to a file</source> @@ -2572,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> @@ -2643,7 +2651,7 @@ Address: %4 </message> <message> <source>Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)</source> - <translation type="unfinished"/> + <translation>í¬íŠ¸ <port>ì„ í†µí•´ JSON-RPC ì—°ê²° (기본값: 8332 ë˜ëŠ” testnet: 18332)</translation> </message> <message> <source>Accept command line and JSON-RPC commands</source> @@ -2651,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> @@ -2685,7 +2693,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2709,19 +2717,21 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> - <translation type="unfinished"/> + <translation>오류 : 해당 거래는 송금액, 다중 거래, 최근 ìˆ˜ë ¹í•œ ê¸ˆì•¡ì˜ ì‚¬ìš© ë“±ì˜ ì´ìœ ë¡œ 최소 %s ì´ìƒì˜ 송금 수수료가 필요합니다.</translation> </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 <n> megabytes (default: 100)</source> @@ -2745,7 +2755,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> - <translation type="unfinished"/> + <translation>ì´ ë¹Œë“œ ë²„ì „ì€ ì •ì‹ ì¶œì‹œ ì „ í…ŒìŠ¤íŠ¸ì˜ ëª©ì ì´ë©°, 예기치 ì•Šì€ ìœ„í—˜ê³¼ 오류가 ë°œìƒí• 수 있습니다. 채굴과 ìƒì ìš© 소프트웨어로 사용하는 ê²ƒì„ ê¶Œí•˜ì§€ 않습니다.</translation> </message> <message> <source>Unable to bind to %s on this computer. Bitcoin Core is probably already running.</source> @@ -2765,7 +2775,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> - <translation type="unfinished"/> + <translation>ê²½ê³ : ëª¨ë“ ë„¤íŠ¸ì›Œí¬ê°€ ë™ì˜í•´ì•¼ 하나, ì¼ë¶€ 채굴ìžë“¤ì—게 ë¬¸ì œê°€ 있는 것으로 보입니다. </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> @@ -2773,19 +2783,19 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </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> - <translation type="unfinished"/> + <translation>ê²½ê³ : wallet.dat 파ì¼ì„ ì½ëŠ” 중 ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 주소 키는 ëª¨ë‘ ì •í™•í•˜ê²Œ 로딩ë˜ì—ˆìœ¼ë‚˜ 거래 ë°ì´í„°ì™€ ì£¼ì†Œë¡ í•„ë“œì—ì„œ 누ë½ì´ë‚˜ 오류가 ì¡´ìž¬í• ìˆ˜ 있습니다. </translation> </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 type="unfinished"/> + <translation>ê²½ê³ : wallet.datê°€ ì†ìƒë˜ì–´ ë°ì´í„°ê°€ 복구ë˜ì—ˆìŠµë‹ˆë‹¤. ì›ëž˜ì˜ wallet.dat 파ì¼ì€ %s í›„ì— wallet.{timestamp}.bak ì´ë¦„으로 ì €ìž¥ë©ë‹ˆë‹¤. 잔액과 거래 ë‚´ì—ì´ ì •í™•í•˜ì§€ 않다면 백업 파ì¼ë¡œ 부터 ë³µì›í•´ì•¼ 합니다. </translation> </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><category> can be:</source> @@ -2821,7 +2831,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Connection options:</source> - <translation type="unfinished"/> + <translation>ì—°ê²° ì„¤ì • : </translation> </message> <message> <source>Corrupted block database detected</source> @@ -2829,11 +2839,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2853,7 +2863,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2921,11 +2931,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2933,7 +2943,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -2949,11 +2959,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Importing...</source> - <translation type="unfinished"/> + <translation>들여오기 중...</translation> </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: '%s'</source> @@ -2961,7 +2971,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Not enough file descriptors available.</source> - <translation type="unfinished"/> + <translation>사용 가능한 íŒŒì¼ ë””ìŠ¤í¬ë¦½í„°-File Descriptor-ê°€ 부족합니다. </translation> </message> <message> <source>Prepend debug output with timestamp (default: 1)</source> @@ -2973,7 +2983,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Rebuild block chain index from current blk000??.dat files</source> - <translation type="unfinished"/> + <translation>í˜„ìž¬ì˜ blk000??.dat 파ì¼ë“¤ë¡œë¶€í„° 블ë¡ì²´ì¸ 색ì¸ì„ 재구성합니다.</translation> </message> <message> <source>Select SOCKS version for -proxy (4 or 5, default: 5)</source> @@ -2989,7 +2999,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Set the number of threads to service RPC calls (default: 4)</source> - <translation type="unfinished"/> + <translation>ì›ê²© í”„ë¡œì‹œì ¸ 호출 서비스를 위한 ì“°ë ˆë“œ 개수를 ì„¤ì •í•©ë‹ˆë‹¤ (기본값 : 4)</translation> </message> <message> <source>Specify wallet file (within data directory)</source> @@ -3033,11 +3043,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>You need to rebuild the database using -reindex to change -txindex</source> - <translation type="unfinished"/> + <translation>-txindex를 바꾸기 위해서는 -reindex를 사용해서 ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 재구성해야 합니다. </translation> </message> <message> <source>Imports blocks from external blk000??.dat file</source> - <translation>외부 blk000??.dat 파ì¼ì—ì„œ ë¸”ë¡ ê°€ì ¸ì˜¤ê¸°</translation> + <translation>외부 blk000??.dat 파ì¼ì—ì„œ 블ë¡ì„ ê°€ì ¸ì˜µë‹ˆë‹¤.</translation> </message> <message> <source>Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running.</source> @@ -3045,7 +3055,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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 <category> is optional)</source> @@ -3053,7 +3063,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3061,19 +3071,19 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Invalid amount for -minrelaytxfee=<amount>: '%s'</source> - <translation type="unfinished"/> + <translation>노드로 ì „ë‹¬í•˜ê¸° 위한 ìµœì € 거래 수수료가 부족합니다. - minrelaytxfee=<amount>: '%s' -</translation> </message> <message> <source>Invalid amount for -mintxfee=<amount>: '%s'</source> - <translation type="unfinished"/> + <translation>ìµœì € 거래 수수료가 부족합니다. -mintxfee=<amount>: '%s'</translation> </message> <message> <source>Limit size of signature cache to <n> entries (default: 50000)</source> - <translation type="unfinished"/> + <translation><n>번 째 순서ì—ì„œ ì „ìžì„œëª… ìºì‰¬ì˜ ìš©ëŸ‰ì„ ì œí•œí•©ë‹ˆë‹¤. (기본값: 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> @@ -3081,11 +3091,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)</source> - <translation type="unfinished"/> + <translation>최대 연결마다 1000bytes 버í¼ë¥¼ 받는다. (기본값: 5000)</translation> </message> <message> <source>Maximum per-connection send buffer, <n>*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> @@ -3093,27 +3103,27 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Only connect to nodes in network <net> (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 <n> network messages</source> - <translation type="unfinished"/> + <translation>ëª¨ë“ ë„¤íŠ¸ì›Œí¬ ë©”ì‹œì§€ 마다 무작위로 1ì´ ë–¨ì–´ì§„ë‹¤</translation> </message> <message> <source>Randomly fuzz 1 of every <n> network messages</source> @@ -3129,7 +3139,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3141,15 +3151,15 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3165,7 +3175,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Start Bitcoin Core Daemon</source> - <translation type="unfinished"/> + <translation>ë¹„íŠ¸ì½”ì¸ ì½”ì–´ì˜ ë°ëª¬ í”„ë¡œê·¸ëž¨ì„ ì‹¤í–‰í•©ë‹ˆë‹¤.</translation> </message> <message> <source>System error: </source> @@ -3209,7 +3219,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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_ky.ts b/src/qt/locale/bitcoin_ky.ts index 375e72d359..d0db034e86 100644 --- a/src/qt/locale/bitcoin_ky.ts +++ b/src/qt/locale/bitcoin_ky.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ky" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ky" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts index 89f4be8202..425519514a 100644 --- a/src/qt/locale/bitcoin_la.ts +++ b/src/qt/locale/bitcoin_la.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="la" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="la" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1047,6 +1047,14 @@ Inscriptio: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1348,7 +1356,7 @@ Inscriptio: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index 103cd5f53d..c74fd8ab3b 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="lt" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="lt" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1046,6 +1046,14 @@ Adresas: %4</translation> <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1347,7 +1355,7 @@ Adresas: %4</translation> <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> @@ -1482,7 +1490,7 @@ Adresas: %4</translation> </message> <message> <source>Welcome to the Bitcoin RPC console.</source> - <translation type="unfinished"/> + <translation>Sveiki atvykÄ™ į Bitcoin RPC konsolÄ™.</translation> </message> <message> <source>Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.</source> @@ -2625,7 +2633,7 @@ Adresas: %4</translation> </message> <message> <source>Specify your own public address</source> - <translation type="unfinished"/> + <translation>Nurodykite savo nuosavÄ… vieÅ¡Ä… adresÄ…</translation> </message> <message> <source>Threshold for disconnecting misbehaving peers (default: 100)</source> @@ -3339,7 +3347,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Cannot write default address</source> - <translation type="unfinished"/> + <translation>Negalima paraÅ¡yti įprasto adreso</translation> </message> <message> <source>Rescanning...</source> diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts index 0db0b77a47..299e4d55e0 100644 --- a/src/qt/locale/bitcoin_lv_LV.ts +++ b/src/qt/locale/bitcoin_lv_LV.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="lv_LV" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="lv_LV" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -16,7 +16,12 @@ 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.</source> - <translation type="unfinished"/> + <translation> +Å Ä« ir eksperimentÄlÄ programmatÅ«ra. + +IzplatÄ«ta saskaÅ†Ä ar MIT/X11 programmatÅ«ras licenci, skatÄ«t pievienoto datni COPYING vai http://www.opensource.org/licenses/mit-license.php. + +Å is produkts ietver programmatÅ«ru, ko izstrÄdÄjis OpenSSL Project izmantoÅ¡anai OpenSSL Toolkit (http://www.openssl.org/) un Å¡ifrÄ“Å¡anas programmatÅ«ru no Eric Young (eay@cryptsoft.com) un UPnP programmatÅ«ru no Thomas Bernard.</translation> </message> <message> <source>Copyright</source> @@ -28,7 +33,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>(%1-bit)</source> - <translation type="unfinished"/> + <translation>(%1-biti)</translation> </message> </context> <context> @@ -63,7 +68,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Delete the currently selected address from the list</source> - <translation type="unfinished"/> + <translation>IzdzÄ“st iezÄ«mÄ“tÄs adreses no saraksta</translation> </message> <message> <source>Export the data in the current tab to a file</source> @@ -79,11 +84,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Choose the address to send coins to</source> - <translation type="unfinished"/> + <translation>IzvÄ“lies adresi uz kuru sÅ«tÄ«t bitcoins</translation> </message> <message> <source>Choose the address to receive coins with</source> - <translation type="unfinished"/> + <translation>IzvÄ“lies adresi ar kuru saņemt bitcoins</translation> </message> <message> <source>C&hoose</source> @@ -201,11 +206,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> - <translation type="unfinished"/> + <translation>BrÄ«dinÄjums: Ja tu noÅ¡ifrÄ“ savu maciņu un pazaudÄ“ paroli, tu <b>PAZAUDÄ’SI VISAS SAVAS BITCOINS</b>!</translation> </message> <message> <source>Are you sure you wish to encrypt your wallet?</source> - <translation type="unfinished"/> + <translation>Vai tu tieÅ¡Äm vÄ“lies Å¡ifrÄ“t savu maciņu?</translation> </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> @@ -249,7 +254,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Wallet passphrase was successfully changed.</source> - <translation type="unfinished"/> + <translation>Maciņa parole tika veiksmÄ«gi nomainÄ«ta.</translation> </message> </context> <context> @@ -268,7 +273,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Node</source> - <translation type="unfinished"/> + <translation>Node</translation> </message> <message> <source>Show general overview of wallet</source> @@ -304,31 +309,31 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&Options...</source> - <translation>&IespÄ“jas</translation> + <translation>&IespÄ“jas...</translation> </message> <message> <source>&Encrypt Wallet...</source> - <translation>Å &ifrÄ“t maciņu...</translation> + <translation>Å ifrÄ“t &maciņu...</translation> </message> <message> <source>&Backup Wallet...</source> - <translation>&Izveidot maciņa rezerves kopiju</translation> + <translation>&Maciņa Rezerves Kopija...</translation> </message> <message> <source>&Change Passphrase...</source> - <translation>&MainÄ«t paroli</translation> + <translation>MainÄ«t &Paroli...</translation> </message> <message> <source>&Sending addresses...</source> - <translation>&AdreÅ¡u sÅ«tÄ«Å¡ana...</translation> + <translation>&SÅ«tÄ«Å¡anas adreses...</translation> </message> <message> <source>&Receiving addresses...</source> - <translation>AdreÅ¡u &saņemÅ¡ana...</translation> + <translation>SaņemÅ¡anas &adreses...</translation> </message> <message> <source>Open &URI...</source> - <translation>AtvÄ“rt &URI</translation> + <translation>AtvÄ“rt &URI...</translation> </message> <message> <source>Importing blocks from disk...</source> @@ -356,7 +361,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&Debug window</source> - <translation>&Debug logs</translation> + <translation>&AtkļūdoÅ¡anas logs</translation> </message> <message> <source>Open debugging and diagnostic console</source> @@ -388,7 +393,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Show or hide the main Window</source> - <translation type="unfinished"/> + <translation>ParÄdÄ«t vai paslÄ“pt galveno Logu</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> @@ -428,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished"/> + <translation>PieprasÄ«t maksÄjumus (izveido QR kodu un bitcoin: URIs)</translation> </message> <message> <source>&About Bitcoin Core</source> @@ -496,7 +501,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>%1 behind</source> - <translation type="unfinished"/> + <translation>%1 aizmugurÄ“</translation> </message> <message> <source>Last received block was generated %1 ago.</source> @@ -556,7 +561,7 @@ Adrese: %4 </message> <message> <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation type="unfinished"/> + <translation>RadÄs fatÄla kļūda. Bitcoin Core nevar vairs droÅ¡i turpinÄt un tiks izslÄ“gta.</translation> </message> </context> <context> @@ -594,7 +599,7 @@ Adrese: %4 </message> <message> <source>Low Output:</source> - <translation type="unfinished"/> + <translation>Zema Izeja:</translation> </message> <message> <source>After Fee:</source> @@ -606,7 +611,7 @@ Adrese: %4 </message> <message> <source>(un)select all</source> - <translation type="unfinished"/> + <translation>iezÄ«mÄ“t visus</translation> </message> <message> <source>Tree mode</source> @@ -658,11 +663,11 @@ Adrese: %4 </message> <message> <source>Lock unspent</source> - <translation type="unfinished"/> + <translation>AizslÄ“gt neiztÄ“rÄ“to</translation> </message> <message> <source>Unlock unspent</source> - <translation type="unfinished"/> + <translation>AtslÄ“gt neiztÄ“rÄ“to</translation> </message> <message> <source>Copy quantity</source> @@ -686,7 +691,7 @@ Adrese: %4 </message> <message> <source>Copy low output</source> - <translation type="unfinished"/> + <translation>KopÄ“t zemo izeju</translation> </message> <message> <source>Copy change</source> @@ -730,7 +735,7 @@ Adrese: %4 </message> <message> <source>(%1 locked)</source> - <translation type="unfinished"/> + <translation>(%1 aizslÄ“gts)</translation> </message> <message> <source>none</source> @@ -738,7 +743,7 @@ Adrese: %4 </message> <message> <source>Dust</source> - <translation type="unfinished"/> + <translation>Putekļi</translation> </message> <message> <source>yes</source> @@ -856,7 +861,7 @@ Adrese: %4 <name>FreespaceChecker</name> <message> <source>A new data directory will be created.</source> - <translation type="unfinished"/> + <translation>Tiks izveidota jauna datu mape.</translation> </message> <message> <source>name</source> @@ -868,11 +873,11 @@ Adrese: %4 </message> <message> <source>Path already exists, and is not a directory.</source> - <translation type="unfinished"/> + <translation>Å Äds ceļš jau pastÄv un tÄ nav mape.</translation> </message> <message> <source>Cannot create data directory here.</source> - <translation type="unfinished"/> + <translation>Å eit nevar izveidot datu mapi.</translation> </message> </context> <context> @@ -942,11 +947,11 @@ Adrese: %4 </message> <message> <source>Use the default data directory</source> - <translation type="unfinished"/> + <translation>Izmantot noklusÄ“to datu mapi</translation> </message> <message> <source>Use a custom data directory:</source> - <translation type="unfinished"/> + <translation>Izmantot pielÄgotu datu mapi:</translation> </message> <message> <source>Bitcoin</source> @@ -1020,7 +1025,7 @@ Adrese: %4 </message> <message> <source>Size of &database cache</source> - <translation type="unfinished"/> + <translation>&DatubÄzes keÅ¡atmiņas izmÄ“rs</translation> </message> <message> <source>MB</source> @@ -1028,31 +1033,39 @@ Adrese: %4 </message> <message> <source>Number of script &verification threads</source> - <translation type="unfinished"/> + <translation>Skriptu &pÄrbaudes pavedienu skaits</translation> </message> <message> <source>Connect to the Bitcoin network through a SOCKS proxy.</source> - <translation type="unfinished"/> + <translation>Savienoties ar Bitcoin tÄ«klu caur SOCKS starpniekserveri.</translation> </message> <message> <source>&Connect through SOCKS proxy (default proxy):</source> - <translation type="unfinished"/> + <translation>&Savienoties caur SOCKS starpniekserveri (noklusÄ“juma starpniekserveris)</translation> </message> <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <translation>Starpniekservera IP adrese (piem. 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"/> </message> <message> + <source>Third party transaction URLs</source> + <translation>TreÅ¡o personu transakciju URLs</translation> + </message> + <message> <source>Active command-line options that override above options:</source> - <translation type="unfinished"/> + <translation>AktÄ«vÄs komandrindas opcijas, kuras pÄrspÄ“ko Å¡os iestatÄ«jumus:</translation> </message> <message> <source>Reset all client options to default.</source> - <translation type="unfinished"/> + <translation>AtiestatÄ«t visus klienta iestatÄ«jumus uz noklusÄ“jumu.</translation> </message> <message> <source>&Reset Options</source> - <translation type="unfinished"/> + <translation>&AtiestatÄ«t IestatÄ«jumus.</translation> </message> <message> <source>&Network</source> @@ -1092,7 +1105,7 @@ Adrese: %4 </message> <message> <source>Proxy &IP:</source> - <translation>Proxy &IP:</translation> + <translation>Starpniekservera &IP:</translation> </message> <message> <source>&Port:</source> @@ -1100,7 +1113,7 @@ Adrese: %4 </message> <message> <source>Port of the proxy (e.g. 9050)</source> - <translation>Proxy ports (piem. 9050)</translation> + <translation>Starpniekservera ports (piem. 9050)</translation> </message> <message> <source>SOCKS &Version:</source> @@ -1108,7 +1121,7 @@ Adrese: %4 </message> <message> <source>SOCKS version of the proxy (e.g. 5)</source> - <translation>proxy SOCKS versija (piem. 5)</translation> + <translation>Starpniekservera SOCKS versija (piem. 5)</translation> </message> <message> <source>&Window</source> @@ -1164,7 +1177,7 @@ Adrese: %4 </message> <message> <source>&OK</source> - <translation>&OK</translation> + <translation>&Labi</translation> </message> <message> <source>&Cancel</source> @@ -1176,11 +1189,11 @@ Adrese: %4 </message> <message> <source>none</source> - <translation>neviens</translation> + <translation>neviena</translation> </message> <message> <source>Confirm options reset</source> - <translation type="unfinished"/> + <translation>ApstiprinÄt iestatÄ«jumu atiestatÄ«Å¡anu</translation> </message> <message> <source>Client restart required to activate changes.</source> @@ -1188,7 +1201,7 @@ Adrese: %4 </message> <message> <source>Client will be shutdown, do you want to proceed?</source> - <translation type="unfinished"/> + <translation>Klients tiks izslÄ“gts, vai vÄ“laties turpinÄt?</translation> </message> <message> <source>This change would require a client restart.</source> @@ -1196,7 +1209,7 @@ Adrese: %4 </message> <message> <source>The supplied proxy address is invalid.</source> - <translation>NorÄdÄ«tÄ proxy adrese nav derÄ«ga.</translation> + <translation>NorÄdÄ«tÄ starpniekservera adrese nav derÄ«ga.</translation> </message> </context> <context> @@ -1223,11 +1236,11 @@ Adrese: %4 </message> <message> <source>Pending:</source> - <translation type="unfinished"/> + <translation>NeizÅ¡Ä·irts:</translation> </message> <message> <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> - <translation type="unfinished"/> + <translation>KopÄ“jÄ apstiprinÄmo transakciju vÄ“rtÄ«ba, vÄ“l nav ieskaitÄ«ta tÄ“rÄ“jamajÄ bilancÄ“</translation> </message> <message> <source>Immature:</source> @@ -1239,7 +1252,7 @@ Adrese: %4 </message> <message> <source>Total:</source> - <translation>KopÄ:</translation> + <translation>Kopsumma:</translation> </message> <message> <source>Your current total balance</source> @@ -1258,7 +1271,7 @@ Adrese: %4 <name>PaymentServer</name> <message> <source>URI handling</source> - <translation type="unfinished"/> + <translation>URI apstrÄde</translation> </message> <message> <source>URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> @@ -1270,11 +1283,11 @@ Adrese: %4 </message> <message> <source>Payment request error</source> - <translation type="unfinished"/> + <translation>MaksÄjumu pieprasÄ«juma kļūda</translation> </message> <message> <source>Cannot start bitcoin: click-to-pay handler</source> - <translation type="unfinished"/> + <translation>Nevar palaist Bitcoin: nospied-lai-maksÄtu apstrÄdÄtÄju</translation> </message> <message> <source>Net manager warning</source> @@ -1302,7 +1315,7 @@ Adrese: %4 </message> <message> <source>Refund from %1</source> - <translation type="unfinished"/> + <translation>Atmaksa no %1</translation> </message> <message> <source>Error communicating with %1: %2</source> @@ -1318,11 +1331,11 @@ Adrese: %4 </message> <message> <source>Payment acknowledged</source> - <translation type="unfinished"/> + <translation>MaksÄjums atzÄ«ts</translation> </message> <message> <source>Network request error</source> - <translation type="unfinished"/> + <translation>TÄ«kla pieprasÄ«juma kļūda</translation> </message> </context> <context> @@ -1344,8 +1357,8 @@ Adrese: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> - <translation type="unfinished"/> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>Bitcoin Core vel neizgÄja droÅ¡i...</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -1391,11 +1404,11 @@ Adrese: %4 </message> <message> <source>Debug window</source> - <translation type="unfinished"/> + <translation>AtkļūdoÅ¡anas logs</translation> </message> <message> <source>General</source> - <translation type="unfinished"/> + <translation>VispÄrÄ“js</translation> </message> <message> <source>Using OpenSSL version</source> @@ -1455,11 +1468,11 @@ Adrese: %4 </message> <message> <source>In:</source> - <translation type="unfinished"/> + <translation>Ie.:</translation> </message> <message> <source>Out:</source> - <translation type="unfinished"/> + <translation>Iz.:</translation> </message> <message> <source>Build date</source> @@ -1467,7 +1480,7 @@ Adrese: %4 </message> <message> <source>Debug log file</source> - <translation type="unfinished"/> + <translation>AtkļūdoÅ¡anas žurnÄla datne</translation> </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> @@ -1538,7 +1551,7 @@ Adrese: %4 </message> <message> <source>R&euse an existing receiving address (not recommended)</source> - <translation type="unfinished"/> + <translation>&AtkÄrtoti izmantot esoÅ¡o saņemÅ¡anas adresi (nav ieteicams)</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> @@ -1574,7 +1587,7 @@ Adrese: %4 </message> <message> <source>Show the selected request (does the same as double clicking an entry)</source> - <translation type="unfinished"/> + <translation>ParÄdÄ«t atlasÄ«tos pieprasÄ«jumus (tas pats, kas dubultklikÅ¡Ä·is uz ieraksta)</translation> </message> <message> <source>Show</source> @@ -1582,7 +1595,7 @@ Adrese: %4 </message> <message> <source>Remove the selected entries from the list</source> - <translation type="unfinished"/> + <translation>Noņemt atlasÄ«tos ierakstus no saraksta.</translation> </message> <message> <source>Remove</source> @@ -1617,7 +1630,7 @@ Adrese: %4 </message> <message> <source>&Save Image...</source> - <translation>&SaglabÄt AttÄ“lu</translation> + <translation>&SaglabÄt AttÄ“lu...</translation> </message> <message> <source>Request payment to %1</source> @@ -1699,15 +1712,15 @@ Adrese: %4 </message> <message> <source>Inputs...</source> - <translation type="unfinished"/> + <translation>Ieejas...</translation> </message> <message> <source>automatically selected</source> - <translation type="unfinished"/> + <translation>automÄtiski atlasÄ«ts</translation> </message> <message> <source>Insufficient funds!</source> - <translation type="unfinished"/> + <translation>Nepietiekami lÄ«dzekļi!</translation> </message> <message> <source>Quantity:</source> @@ -1731,7 +1744,7 @@ Adrese: %4 </message> <message> <source>Low Output:</source> - <translation type="unfinished"/> + <translation>Zema Izeja:</translation> </message> <message> <source>After Fee:</source> @@ -1811,7 +1824,7 @@ Adrese: %4 </message> <message> <source>Copy low output</source> - <translation type="unfinished"/> + <translation>KopÄ“t zemÄs izejas</translation> </message> <message> <source>Copy change</source> @@ -1827,7 +1840,7 @@ Adrese: %4 </message> <message> <source>The recipient address is not valid, please recheck.</source> - <translation type="unfinished"/> + <translation>SaņēmÄ“ja adrese ir nepareiza, lÅ«dzu pÄrbaudi.</translation> </message> <message> <source>The amount to pay must be larger than 0.</source> @@ -1855,7 +1868,7 @@ Adrese: %4 </message> <message> <source>Warning: Invalid Bitcoin address</source> - <translation type="unfinished"/> + <translation>BrÄ«dinÄjums: NederÄ«ga Bitcoin adrese</translation> </message> <message> <source>(no label)</source> @@ -1863,7 +1876,7 @@ Adrese: %4 </message> <message> <source>Warning: Unknown change address</source> - <translation type="unfinished"/> + <translation>BrÄ«dinÄjums: NezinÄma atlikuma adrese</translation> </message> <message> <source>Are you sure you want to send?</source> @@ -1879,7 +1892,7 @@ Adrese: %4 </message> <message> <source>Invalid payment address %1</source> - <translation type="unfinished"/> + <translation>NederÄ«ga maksÄjuma adrese %1</translation> </message> </context> <context> @@ -1906,7 +1919,7 @@ Adrese: %4 </message> <message> <source>Choose previously used address</source> - <translation type="unfinished"/> + <translation>IzvÄ“lies iepriekÅ¡ izmantoto adresi</translation> </message> <message> <source>This is a normal payment.</source> @@ -1954,7 +1967,7 @@ Adrese: %4 </message> <message> <source>Memo:</source> - <translation type="unfinished"/> + <translation>Memo:</translation> </message> </context> <context> @@ -1965,7 +1978,7 @@ Adrese: %4 </message> <message> <source>Do not shut down the computer until this window disappears.</source> - <translation type="unfinished"/> + <translation>NeizslÄ“dziet datoru kamÄ“r Å¡is logs nepazÅ«d.</translation> </message> </context> <context> @@ -1984,11 +1997,11 @@ Adrese: %4 </message> <message> <source>The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> - <translation type="unfinished"/> + <translation>Adrese ar kuru parakstÄ«t ziņojumu (piem. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation> </message> <message> <source>Choose previously used address</source> - <translation type="unfinished"/> + <translation>IzvÄ“lies iepriekÅ¡ izmantoto adresi</translation> </message> <message> <source>Alt+A</source> @@ -2004,7 +2017,7 @@ Adrese: %4 </message> <message> <source>Enter the message you want to sign here</source> - <translation type="unfinished"/> + <translation>Å eit ievadi ziņojumu kuru vÄ“lies parakstÄ«t</translation> </message> <message> <source>Signature</source> @@ -2012,11 +2025,11 @@ Adrese: %4 </message> <message> <source>Copy the current signature to the system clipboard</source> - <translation type="unfinished"/> + <translation>KopÄ“t parakstu uz sistÄ“mas starpliktuvi</translation> </message> <message> <source>Sign the message to prove you own this Bitcoin address</source> - <translation type="unfinished"/> + <translation>ParakstÄ«t ziņojumu lai pierÄdÄ«tu, ka esi Å¡Ä«s Bitcoin adreses Ä«paÅ¡nieks.</translation> </message> <message> <source>Sign &Message</source> @@ -2024,7 +2037,7 @@ Adrese: %4 </message> <message> <source>Reset all sign message fields</source> - <translation type="unfinished"/> + <translation>AtiestatÄ«t visus laukus</translation> </message> <message> <source>Clear &All</source> @@ -2040,7 +2053,7 @@ Adrese: %4 </message> <message> <source>The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> - <translation type="unfinished"/> + <translation>Adrese ar kÄdu ziņojums tika parakstÄ«ts (piem. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation> </message> <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> @@ -2052,7 +2065,7 @@ Adrese: %4 </message> <message> <source>Reset all verify message fields</source> - <translation type="unfinished"/> + <translation>AtiestatÄ«t visus laukus</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -2064,23 +2077,23 @@ Adrese: %4 </message> <message> <source>The entered address is invalid.</source> - <translation type="unfinished"/> + <translation>IevadÄ«tÄ adrese ir nederÄ«ga.</translation> </message> <message> <source>Please check the address and try again.</source> - <translation type="unfinished"/> + <translation>LÅ«dzu pÄrbaudi adresi un mÄ“Ä£ini vÄ“lreiz.</translation> </message> <message> <source>The entered address does not refer to a key.</source> - <translation type="unfinished"/> + <translation>IevadÄ«tÄ adrese neattiecas uz atslÄ“gu.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> - <translation type="unfinished"/> + <translation>Maciņa atslÄ“gÅ¡ana tika atcelta.</translation> </message> <message> <source>Private key for the entered address is not available.</source> - <translation type="unfinished"/> + <translation>PrivÄtÄ atslÄ“ga priekÅ¡ ievadÄ«tÄs adreses nav pieejama.</translation> </message> <message> <source>Message signing failed.</source> @@ -2096,11 +2109,11 @@ Adrese: %4 </message> <message> <source>Please check the signature and try again.</source> - <translation type="unfinished"/> + <translation>LÅ«dzu pÄrbaudi parakstu un mÄ“Ä£ini vÄ“lreiz.</translation> </message> <message> <source>The signature did not match the message digest.</source> - <translation type="unfinished"/> + <translation>Paraksts neatbilda ziņojuma apkopojumam.</translation> </message> <message> <source>Message verification failed.</source> @@ -2141,7 +2154,7 @@ Adrese: %4 </message> <message> <source>conflicted</source> - <translation type="unfinished"/> + <translation>pretrunÄ</translation> </message> <message> <source>%1/offline</source> @@ -2173,7 +2186,7 @@ Adrese: %4 </message> <message> <source>Generated</source> - <translation type="unfinished"/> + <translation>Ä¢enerÄ“ts</translation> </message> <message> <source>From</source> @@ -2185,15 +2198,15 @@ Adrese: %4 </message> <message> <source>own address</source> - <translation type="unfinished"/> + <translation>paÅ¡a adrese</translation> </message> <message> <source>label</source> - <translation type="unfinished"/> + <translation>etiÄ·ete</translation> </message> <message> <source>Credit</source> - <translation type="unfinished"/> + <translation>KredÄ«ts</translation> </message> <message numerus="yes"> <source>matures in %n more block(s)</source> @@ -2201,11 +2214,11 @@ Adrese: %4 </message> <message> <source>not accepted</source> - <translation type="unfinished"/> + <translation>nav pieņemts</translation> </message> <message> <source>Debit</source> - <translation type="unfinished"/> + <translation>Debets</translation> </message> <message> <source>Transaction fee</source> @@ -2229,7 +2242,7 @@ Adrese: %4 </message> <message> <source>Merchant</source> - <translation type="unfinished"/> + <translation>TirgotÄjs</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 "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> @@ -2237,7 +2250,7 @@ Adrese: %4 </message> <message> <source>Debug information</source> - <translation type="unfinished"/> + <translation>AtkļūdoÅ¡anas informÄcija</translation> </message> <message> <source>Transaction</source> @@ -2245,7 +2258,7 @@ Adrese: %4 </message> <message> <source>Inputs</source> - <translation type="unfinished"/> + <translation>Ieejas</translation> </message> <message> <source>Amount</source> @@ -2265,7 +2278,7 @@ Adrese: %4 </message> <message numerus="yes"> <source>Open for %n more block(s)</source> - <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation> + <translation><numerusform>AtvÄ“rts vel %n blokus</numerusform><numerusform>AtvÄ“rts vel %n bloku</numerusform><numerusform>AtvÄ“rts vel %n blokus</numerusform></translation> </message> <message> <source>unknown</source> @@ -2307,7 +2320,7 @@ Adrese: %4 </message> <message numerus="yes"> <source>Open for %n more block(s)</source> - <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation> + <translation><numerusform>AtvÄ“rts vel %n blokus</numerusform><numerusform>AtvÄ“rts vel %n bloku</numerusform><numerusform>AtvÄ“rts vel %n blokus</numerusform></translation> </message> <message> <source>Open until %1</source> @@ -2339,7 +2352,7 @@ Adrese: %4 </message> <message> <source>Conflicted</source> - <translation type="unfinished"/> + <translation>PretrunÄ</translation> </message> <message> <source>Received with</source> @@ -2486,7 +2499,7 @@ Adrese: %4 </message> <message> <source>The transaction history was successfully saved to %1.</source> - <translation type="unfinished"/> + <translation>Transakciju vÄ“sture tika veiksmÄ«gi saglabÄta uz %1.</translation> </message> <message> <source>Comma separated file (*.csv)</source> @@ -2547,7 +2560,7 @@ Adrese: %4 <name>WalletView</name> <message> <source>&Export</source> - <translation>&EksportÄ“t...</translation> + <translation>&EksportÄ“t</translation> </message> <message> <source>Export the data in the current tab to a file</source> @@ -2646,7 +2659,7 @@ Adrese: %4 </message> <message> <source>Bitcoin Core RPC client version</source> - <translation type="unfinished"/> + <translation>Bitcoin Core RPC klienta versija</translation> </message> <message> <source>Run in the background as a daemon and accept commands</source> @@ -2756,7 +2769,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin will not work properly.</source> - <translation type="unfinished"/> + <translation>BrÄ«dinÄjums: LÅ«dzu pÄrbaudi vai tava datora datums un laiks ir pareizs! Ja pulkstenis ir nepareizs, Bitcoin Core nestrÄdÄs pareizi.</translation> </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> @@ -2776,11 +2789,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>(default: 1)</source> - <translation type="unfinished"/> + <translation>(noklusÄ“jums: 1)</translation> </message> <message> <source>(default: wallet.dat)</source> - <translation type="unfinished"/> + <translation>(noklusÄ“jums: wallet.dat)</translation> </message> <message> <source><category> can be:</source> @@ -2788,7 +2801,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation type="unfinished"/> + <translation>MÄ“Ä£inÄt atgÅ«t privÄtÄs atslÄ“gas no bojÄta wallet.dat</translation> </message> <message> <source>Bitcoin Core Daemon</source> @@ -2804,11 +2817,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Connect only to the specified node(s)</source> - <translation type="unfinished"/> + <translation>Savienoties tikai ar norÄdÄ«tajÄm nodÄ“m.</translation> </message> <message> <source>Connect through SOCKS proxy</source> - <translation type="unfinished"/> + <translation>Savienoties caur SOCKS starpniekserveri</translation> </message> <message> <source>Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)</source> @@ -2816,7 +2829,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Connection options:</source> - <translation type="unfinished"/> + <translation>Savienojuma iestatÄ«jumi:</translation> </message> <message> <source>Corrupted block database detected</source> @@ -2824,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Debugging/Testing options:</source> - <translation type="unfinished"/> + <translation>AtkļūdoÅ¡anas/TestÄ“Å¡anas iestatÄ«jumi:</translation> </message> <message> <source>Disable safemode, override a real safe mode event (default: 0)</source> @@ -2852,7 +2865,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Error loading block database</source> - <translation type="unfinished"/> + <translation>Kļūda ielÄdÄ“jot bloku datubÄzi</translation> </message> <message> <source>Error opening block database</source> @@ -2860,15 +2873,15 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Error: Disk space is low!</source> - <translation type="unfinished"/> + <translation>Kļūda: Zema diska vieta!</translation> </message> <message> <source>Error: Wallet locked, unable to create transaction!</source> - <translation type="unfinished"/> + <translation>Kļūda: Maciņš ir aizslÄ“gts, nevar izveidot transakciju!</translation> </message> <message> <source>Error: system error: </source> - <translation type="unfinished"/> + <translation>Kļūda: sistÄ“mas kļūda:</translation> </message> <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> @@ -2924,11 +2937,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Find peers using DNS lookup (default: 1 unless -connect)</source> - <translation type="unfinished"/> + <translation>Atrast pÄ«rus izmantojot DNS uzmeklÄ“Å¡anu (noklusÄ“jums: 1 ja nav -connect)</translation> </message> <message> <source>Force safe mode (default: 0)</source> - <translation type="unfinished"/> + <translation>Piespiest droÅ¡o režīmu (noklusÄ“jums: 0)</translation> </message> <message> <source>Generate coins (default: 0)</source> @@ -2944,7 +2957,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Importing...</source> - <translation type="unfinished"/> + <translation>ImportÄ“...</translation> </message> <message> <source>Incorrect or no genesis block found. Wrong datadir for network?</source> @@ -2992,7 +3005,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Spend unconfirmed change when sending transactions (default: 1)</source> - <translation type="unfinished"/> + <translation>TÄ“rÄ“t neapstiprinÄtu atlikumu kad sÅ«ta transakcijas (noklusÄ“jums: 1)</translation> </message> <message> <source>This is intended for regression testing tools and app development.</source> @@ -3012,7 +3025,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Wait for RPC server to start</source> - <translation type="unfinished"/> + <translation>Uzgaidi lÄ«dz RPC serveris palaižas</translation> </message> <message> <source>Wallet %s resides outside data directory %s</source> @@ -3032,7 +3045,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Imports blocks from external blk000??.dat file</source> - <translation type="unfinished"/> + <translation>ImportÄ“t blokus no ÄrÄ“jÄs blk000??.dat datnes</translation> </message> <message> <source>Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running.</source> @@ -3104,7 +3117,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>RPC server options:</source> - <translation type="unfinished"/> + <translation>RPC servera iestatÄ«jumi:</translation> </message> <message> <source>Randomly drop 1 of every <n> network messages</source> @@ -3124,7 +3137,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Send command to Bitcoin Core</source> - <translation type="unfinished"/> + <translation>SÅ«tÄ«t komandu uz Bitcoin Core</translation> </message> <message> <source>Send trace/debug info to console instead of debug.log file</source> @@ -3144,7 +3157,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Show benchmark information (default: 0)</source> - <translation type="unfinished"/> + <translation>RÄdÄ«t etalonuzdevuma informÄciju (noklusÄ“jums: 0)</translation> </message> <message> <source>Shrink debug.log file on client startup (default: 1 when no -debug)</source> @@ -3152,7 +3165,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Signing transaction failed</source> - <translation type="unfinished"/> + <translation>Transakcijas parakstÄ«Å¡ana neizdevÄs</translation> </message> <message> <source>Specify connection timeout in milliseconds (default: 5000)</source> @@ -3160,19 +3173,19 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Start Bitcoin Core Daemon</source> - <translation type="unfinished"/> + <translation>SÄkt Bitcoin Core Procesu</translation> </message> <message> <source>System error: </source> - <translation type="unfinished"/> + <translation>SistÄ“mas kļūda:</translation> </message> <message> <source>Transaction amount too small</source> - <translation type="unfinished"/> + <translation>Transakcijas summa ir pÄrÄk maza</translation> </message> <message> <source>Transaction amounts must be positive</source> - <translation type="unfinished"/> + <translation>Transakcijas summai ir jÄbÅ«t pozitÄ«vai</translation> </message> <message> <source>Transaction too large</source> @@ -3196,7 +3209,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Warning: This version is obsolete, upgrade required!</source> - <translation type="unfinished"/> + <translation>BrÄ«dinÄjums: Å Ä« versija ir novecojusi, nepiecieÅ¡ams atjauninÄjums!</translation> </message> <message> <source>Zapping all transactions from wallet...</source> @@ -3204,7 +3217,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>on startup</source> - <translation type="unfinished"/> + <translation>startÄ“Å¡anas laikÄ</translation> </message> <message> <source>version</source> @@ -3212,7 +3225,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>wallet.dat corrupt, salvage failed</source> - <translation type="unfinished"/> + <translation>wallet.dat ir bojÄts, glÄbÅ¡ana neizdevÄs</translation> </message> <message> <source>Password for JSON-RPC connections</source> @@ -3296,7 +3309,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Unknown -socks proxy version requested: %i</source> - <translation>PieprasÄ«ta nezinÄma -socks proxy versija: %i</translation> + <translation>PieprasÄ«ta nezinÄma -socks starpniekservera versija: %i</translation> </message> <message> <source>Cannot resolve -bind address: '%s'</source> diff --git a/src/qt/locale/bitcoin_mn.ts b/src/qt/locale/bitcoin_mn.ts new file mode 100644 index 0000000000..e765931b2c --- /dev/null +++ b/src/qt/locale/bitcoin_mn.ts @@ -0,0 +1,3375 @@ +<?xml version="1.0" ?><!DOCTYPE TS><TS language="mn" version="2.1"> +<context> + <name>AboutDialog</name> + <message> + <source>About Bitcoin Core</source> + <translation type="unfinished"/> + </message> + <message> + <source><b>Bitcoin Core</b> version</source> + <translation type="unfinished"/> + </message> + <message> + <source> +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.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copyright</source> + <translation type="unfinished"/> + </message> + <message> + <source>The Bitcoin Core developers</source> + <translation type="unfinished"/> + </message> + <message> + <source>(%1-bit)</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>AddressBookPage</name> + <message> + <source>Double-click to edit address or label</source> + <translation>ХаÑг ÑÑвÑл шошгыг ѳѳрчлѳхийн тулд хоёр удаа дар</translation> + </message> + <message> + <source>Create a new address</source> + <translation>Ð¨Ð¸Ð½Ñ Ñ…Ð°Ñг нÑÑÑ…</translation> + </message> + <message> + <source>&New</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy the currently selected address to the system clipboard</source> + <translation>Одоогоор ÑонгогдÑон байгаа хаÑгуудыг Ñануулах</translation> + </message> + <message> + <source>&Copy</source> + <translation type="unfinished"/> + </message> + <message> + <source>C&lose</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Copy Address</source> + <translation>ХаÑгийг &Хуулбарлах</translation> + </message> + <message> + <source>Delete the currently selected address from the list</source> + <translation type="unfinished"/> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Export</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Delete</source> + <translation>&УÑтгах</translation> + </message> + <message> + <source>Choose the address to send coins to</source> + <translation type="unfinished"/> + </message> + <message> + <source>Choose the address to receive coins with</source> + <translation type="unfinished"/> + </message> + <message> + <source>C&hoose</source> + <translation type="unfinished"/> + </message> + <message> + <source>Sending addresses</source> + <translation type="unfinished"/> + </message> + <message> + <source>Receiving addresses</source> + <translation type="unfinished"/> + </message> + <message> + <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> + <translation type="unfinished"/> + </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"/> + </message> + <message> + <source>Copy &Label</source> + <translation>&Шошгыг хуулбарлах</translation> + </message> + <message> + <source>&Edit</source> + <translation>&Ѳѳрчлѳх</translation> + </message> + <message> + <source>Export Address List</source> + <translation type="unfinished"/> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>ТаÑлалаар туÑгаарлагдÑан Ñ…Ò¯ÑнÑгтÑн файл (.csv)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation type="unfinished"/> + </message> + <message> + <source>There was an error trying to save the address list to %1.</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>AddressTableModel</name> + <message> + <source>Label</source> + <translation>Шошго</translation> + </message> + <message> + <source>Address</source> + <translation>ХаÑг</translation> + </message> + <message> + <source>(no label)</source> + <translation>(шошго алга)</translation> + </message> +</context> +<context> + <name>AskPassphraseDialog</name> + <message> + <source>Passphrase Dialog</source> + <translation type="unfinished"/> + </message> + <message> + <source>Enter passphrase</source> + <translation>Ðууц үгийг оруул</translation> + </message> + <message> + <source>New passphrase</source> + <translation>Ð¨Ð¸Ð½Ñ Ð½ÑƒÑƒÑ† үг</translation> + </message> + <message> + <source>Repeat new passphrase</source> + <translation>Ð¨Ð¸Ð½Ñ Ð½ÑƒÑƒÑ† үгийг давтана уу</translation> + </message> + <message> + <source>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>.</source> + <translation>Түрүйвчийн ÑˆÐ¸Ð½Ñ Ð½ÑƒÑƒÑ† үгийг оруул. <br/><b>Дор хаÑж 10 дурын Ò¯ÑÑг/тоо бүхий</b> ÑÑвÑл <b>дор хаÑж 8 дурын үгнÑÑÑ Ð±Ò¯Ñ€Ð´ÑÑн</b> нууц үгийг ашиглана уу. </translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>Түрүйвчийг цоожлох</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation>ÐÐ½Ñ Ò¯Ð¹Ð»Ð´Ñлийг гүйцÑтгÑхийн тулд та нууц үгÑÑÑ€ÑÑ Ñ‚Ò¯Ñ€Ò¯Ð¹Ð²Ñ‡Ð¸Ð¹Ð½ цоожийг тайлах Ñ…ÑÑ€ÑгтÑй</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation>Түрүйвчийн цоожийг тайлах</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to decrypt the wallet.</source> + <translation>ÐÐ½Ñ Ò¯Ð¹Ð»Ð´Ñлийг гүйцÑтгÑхийн тулд та ÑхлÑÑд түрүйвчийн нууц үгийг оруулж цоожийг тайлах шаардлагтай.</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>Түрүйвчийн цоожийг уÑтгах</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>Ðууц үгийг Ñолих</translation> + </message> + <message> + <source>Enter the old and new passphrase to the wallet.</source> + <translation>Түрүйвчийн хуучин болоод ÑˆÐ¸Ð½Ñ Ð½ÑƒÑƒÑ† үгÑийг оруулна уу</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>Түрүйвчийн цоожийг баталгаажуулах</translation> + </message> + <message> + <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> + <translation type="unfinished"/> + </message> + <message> + <source>Are you sure you wish to encrypt your wallet?</source> + <translation type="unfinished"/> + </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 type="unfinished"/> + </message> + <message> + <source>Warning: The Caps Lock key is on!</source> + <translation type="unfinished"/> + </message> + <message> + <source>Wallet encrypted</source> + <translation>Түрүйвч цоожлогдлоо</translation> + </message> + <message> + <source>Bitcoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>Цоожлолтын процеÑыг дууÑгахын тулд Биткойн одоо хаагдана. Ѳѳрийн түрүйвчийг цоожлох нь таны биткойнуудыг компьютерийн Ð²Ð¸Ñ€ÑƒÑ Ñ…ÑƒÐ»Ð³Ð°Ð¹Ð»Ð°Ñ…Ð°Ð°Ñ Ð±Ò¯Ñ€Ñн ÑÑргийлж чадахгүй гÑдгийг Ñанаарай.</translation> + </message> + <message> + <source>Wallet encryption failed</source> + <translation>Түрүйвчийн цоожлол амжилттай болÑонгүй</translation> + </message> + <message> + <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> + <translation>Түрүйвчийн цоожлол дотоод Ð°Ð»Ð´Ð°Ð°Ð½Ð°Ð°Ñ Ò¯Ò¯Ð´Ñн амжилттай болÑонгүй. Түрүйвч цоожлогдоогүй байна.</translation> + </message> + <message> + <source>The supplied passphrases do not match.</source> + <translation>Таны оруулÑан нууц үг таарÑангүй</translation> + </message> + <message> + <source>Wallet unlock failed</source> + <translation>Түрүйвчийн цоож тайлагдÑангүй</translation> + </message> + <message> + <source>The passphrase entered for the wallet decryption was incorrect.</source> + <translation>Таны оруулÑан түрүйвчийн цоожийг тайлах нууц үг буруу байна</translation> + </message> + <message> + <source>Wallet decryption failed</source> + <translation>Түрүйвчийн цоож амжилттай уÑтгагдÑангүй</translation> + </message> + <message> + <source>Wallet passphrase was successfully changed.</source> + <translation>Түрүйвчийн нууц үг амжилттай ѳѳр</translation> + </message> +</context> +<context> + <name>BitcoinGUI</name> + <message> + <source>Sign &message...</source> + <translation>&Ð—ÑƒÑ€Ð²Ð°Ñ Ñ…Ð°Ð²Ñаргах...</translation> + </message> + <message> + <source>Synchronizing with network...</source> + <translation>СүлжÑÑÑ‚Ñй тааруулж байна...</translation> + </message> + <message> + <source>&Overview</source> + <translation type="unfinished"/> + </message> + <message> + <source>Node</source> + <translation>Ðод</translation> + </message> + <message> + <source>Show general overview of wallet</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Transactions</source> + <translation>ГүйлгÑÑнүүд</translation> + </message> + <message> + <source>Browse transaction history</source> + <translation>ГүйлгÑÑнүүдийн түүхийг харах</translation> + </message> + <message> + <source>E&xit</source> + <translation>Гарах</translation> + </message> + <message> + <source>Quit application</source> + <translation>ÐŸÑ€Ð¾Ð³Ñ€Ð°Ð¼Ð°Ð°Ñ Ð“Ð°Ñ€Ð°Ñ…</translation> + </message> + <message> + <source>Show information about Bitcoin</source> + <translation>Биткойны мÑдÑÑллийг харуулах</translation> + </message> + <message> + <source>About &Qt</source> + <translation>&Клиентийн тухай</translation> + </message> + <message> + <source>Show information about Qt</source> + <translation>Клиентийн тухай мÑдÑÑллийг харуул</translation> + </message> + <message> + <source>&Options...</source> + <translation>&Сонголтууд...</translation> + </message> + <message> + <source>&Encrypt Wallet...</source> + <translation>&Түрүйвчийг цоожлох...</translation> + </message> + <message> + <source>&Backup Wallet...</source> + <translation>&Түрүйвчийг Жоорлох...</translation> + </message> + <message> + <source>&Change Passphrase...</source> + <translation>&Ðууц Үгийг Солих...</translation> + </message> + <message> + <source>&Sending addresses...</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Receiving addresses...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Open &URI...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Importing blocks from disk...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Reindexing blocks on disk...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Send coins to a Bitcoin address</source> + <translation type="unfinished"/> + </message> + <message> + <source>Modify configuration options for Bitcoin</source> + <translation type="unfinished"/> + </message> + <message> + <source>Backup wallet to another location</source> + <translation type="unfinished"/> + </message> + <message> + <source>Change the passphrase used for wallet encryption</source> + <translation>Түрүйвчийг цоожлох нууц үгийг Ñолих</translation> + </message> + <message> + <source>&Debug window</source> + <translation type="unfinished"/> + </message> + <message> + <source>Open debugging and diagnostic console</source> + <translation>Оношилгоо ба заÑварын конÑолыг онгойлго</translation> + </message> + <message> + <source>&Verify message...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Bitcoin</source> + <translation>Биткойн</translation> + </message> + <message> + <source>Wallet</source> + <translation>Түрүйвч</translation> + </message> + <message> + <source>&Send</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Receive</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Show / Hide</source> + <translation>&Харуул / Ðуу</translation> + </message> + <message> + <source>Show or hide the main Window</source> + <translation type="unfinished"/> + </message> + <message> + <source>Encrypt the private keys that belong to your wallet</source> + <translation type="unfinished"/> + </message> + <message> + <source>Sign messages with your Bitcoin addresses to prove you own them</source> + <translation type="unfinished"/> + </message> + <message> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation type="unfinished"/> + </message> + <message> + <source>&File</source> + <translation>&Файл</translation> + </message> + <message> + <source>&Settings</source> + <translation>&Тохиргоо</translation> + </message> + <message> + <source>&Help</source> + <translation>&ТуÑламж</translation> + </message> + <message> + <source>Tabs toolbar</source> + <translation type="unfinished"/> + </message> + <message> + <source>[testnet]</source> + <translation type="unfinished"/> + </message> + <message> + <source>Bitcoin Core</source> + <translation type="unfinished"/> + </message> + <message> + <source>Request payments (generates QR codes and bitcoin: URIs)</source> + <translation type="unfinished"/> + </message> + <message> + <source>&About Bitcoin Core</source> + <translation type="unfinished"/> + </message> + <message> + <source>Show the list of used sending addresses and labels</source> + <translation type="unfinished"/> + </message> + <message> + <source>Show the list of used receiving addresses and labels</source> + <translation type="unfinished"/> + </message> + <message> + <source>Open a bitcoin: URI or payment request</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Command-line options</source> + <translation type="unfinished"/> + </message> + <message> + <source>Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options</source> + <translation type="unfinished"/> + </message> + <message> + <source>Bitcoin client</source> + <translation>Биткойн клиент</translation> + </message> + <message numerus="yes"> + <source>%n active connection(s) to Bitcoin network</source> + <translation><numerusform>Биткойны ÑүлжÑÑÑ€Ò¯Ò¯ %n идÑвхитÑй холболт байна </numerusform><numerusform>Биткойны ÑүлжÑÑÑ€Ò¯Ò¯ %n идÑвхитÑй холболтууд байна </numerusform></translation> + </message> + <message> + <source>No block source available...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Processed %1 of %2 (estimated) blocks of transaction history.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Processed %1 blocks of transaction history.</source> + <translation type="unfinished"/> + </message> + <message numerus="yes"> + <source>%n hour(s)</source> + <translation><numerusform>%n цаг</numerusform><numerusform>%n цаг</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n day(s)</source> + <translation><numerusform>%n ѳдѳр</numerusform><numerusform>%n ѳдрүүд</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n week(s)</source> + <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> + </message> + <message> + <source>%1 and %2</source> + <translation type="unfinished"/> + </message> + <message numerus="yes"> + <source>%n year(s)</source> + <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> + </message> + <message> + <source>%1 behind</source> + <translation type="unfinished"/> + </message> + <message> + <source>Last received block was generated %1 ago.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Transactions after this will not yet be visible.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error</source> + <translation>Ðлдаа</translation> + </message> + <message> + <source>Warning</source> + <translation type="unfinished"/> + </message> + <message> + <source>Information</source> + <translation type="unfinished"/> + </message> + <message> + <source>Up to date</source> + <translation>ШинÑчлÑгдÑÑн</translation> + </message> + <message> + <source>Catching up...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Sent transaction</source> + <translation>Гадагшаа гүйлгÑÑ</translation> + </message> + <message> + <source>Incoming transaction</source> + <translation>Дотогшоо гүйлгÑÑ</translation> + </message> + <message> + <source>Date: %1 +Amount: %2 +Type: %3 +Address: %4 +</source> + <translation>Огноо: %1 + +Ð¥ÑмжÑÑ: %2 + +Тѳрѳл: %3 + +ХаÑг: %4 +</translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> + <translation>Түрүйвч <b>цоожтой</b> ба одоогоор цоож <b>онгорхой</b> байна</translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> + <translation>Түрүйвч <b>цоожтой</b> ба одоогоор цоож <b>хаалттай</b> байна</translation> + </message> + <message> + <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>ClientModel</name> + <message> + <source>Network Alert</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>CoinControlDialog</name> + <message> + <source>Coin Control Address Selection</source> + <translation type="unfinished"/> + </message> + <message> + <source>Quantity:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Bytes:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Amount:</source> + <translation>Ð¥ÑмжÑÑ:</translation> + </message> + <message> + <source>Priority:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Fee:</source> + <translation>Тѳлбѳр:</translation> + </message> + <message> + <source>Low Output:</source> + <translation type="unfinished"/> + </message> + <message> + <source>After Fee:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Change:</source> + <translation type="unfinished"/> + </message> + <message> + <source>(un)select all</source> + <translation type="unfinished"/> + </message> + <message> + <source>Tree mode</source> + <translation type="unfinished"/> + </message> + <message> + <source>List mode</source> + <translation type="unfinished"/> + </message> + <message> + <source>Amount</source> + <translation>Ð¥ÑмжÑÑ</translation> + </message> + <message> + <source>Address</source> + <translation>ХаÑг</translation> + </message> + <message> + <source>Date</source> + <translation>Огноо</translation> + </message> + <message> + <source>Confirmations</source> + <translation type="unfinished"/> + </message> + <message> + <source>Confirmed</source> + <translation>Баталгаажлаа</translation> + </message> + <message> + <source>Priority</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy address</source> + <translation>ХаÑгийг Ñанах</translation> + </message> + <message> + <source>Copy label</source> + <translation>Шошгыг Ñанах</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Ð¥ÑмжÑÑг Ñанах</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation type="unfinished"/> + </message> + <message> + <source>Lock unspent</source> + <translation type="unfinished"/> + </message> + <message> + <source>Unlock unspent</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy quantity</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy fee</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy after fee</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy bytes</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy priority</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy low output</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy change</source> + <translation>Ѳѳрчлѳлтийг Ñанах</translation> + </message> + <message> + <source>highest</source> + <translation type="unfinished"/> + </message> + <message> + <source>higher</source> + <translation type="unfinished"/> + </message> + <message> + <source>high</source> + <translation type="unfinished"/> + </message> + <message> + <source>medium-high</source> + <translation type="unfinished"/> + </message> + <message> + <source>medium</source> + <translation type="unfinished"/> + </message> + <message> + <source>low-medium</source> + <translation type="unfinished"/> + </message> + <message> + <source>low</source> + <translation type="unfinished"/> + </message> + <message> + <source>lower</source> + <translation type="unfinished"/> + </message> + <message> + <source>lowest</source> + <translation type="unfinished"/> + </message> + <message> + <source>(%1 locked)</source> + <translation type="unfinished"/> + </message> + <message> + <source>none</source> + <translation type="unfinished"/> + </message> + <message> + <source>Dust</source> + <translation type="unfinished"/> + </message> + <message> + <source>yes</source> + <translation type="unfinished"/> + </message> + <message> + <source>no</source> + <translation type="unfinished"/> + </message> + <message> + <source>This label turns red, if the transaction size is greater than 1000 bytes.</source> + <translation type="unfinished"/> + </message> + <message> + <source>This means a fee of at least %1 per kB is required.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Can vary +/- 1 byte per input.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Transactions with higher priority are more likely to get included into a block.</source> + <translation type="unfinished"/> + </message> + <message> + <source>This label turns red, if the priority is smaller than "medium".</source> + <translation type="unfinished"/> + </message> + <message> + <source>This label turns red, if any recipient receives an amount smaller than %1.</source> + <translation type="unfinished"/> + </message> + <message> + <source>This means a fee of at least %1 is required.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Amounts below 0.546 times the minimum relay fee are shown as dust.</source> + <translation type="unfinished"/> + </message> + <message> + <source>This label turns red, if the change is smaller than %1.</source> + <translation type="unfinished"/> + </message> + <message> + <source>(no label)</source> + <translation>(шошгогүй)</translation> + </message> + <message> + <source>change from %1 (%2)</source> + <translation type="unfinished"/> + </message> + <message> + <source>(change)</source> + <translation>(ѳѳрчлѳх)</translation> + </message> +</context> +<context> + <name>EditAddressDialog</name> + <message> + <source>Edit Address</source> + <translation>ХаÑгийг ѳѳрчлѳх</translation> + </message> + <message> + <source>&Label</source> + <translation>&Шошго</translation> + </message> + <message> + <source>The label associated with this address list entry</source> + <translation type="unfinished"/> + </message> + <message> + <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Address</source> + <translation>&ХаÑг</translation> + </message> + <message> + <source>New receiving address</source> + <translation>Ð¨Ð¸Ð½Ñ Ñ…Ò¯Ð»ÑÑн авах хаÑг</translation> + </message> + <message> + <source>New sending address</source> + <translation>Ð¨Ð¸Ð½Ñ Ñвуулах хаÑг</translation> + </message> + <message> + <source>Edit receiving address</source> + <translation>ХүлÑÑн авах хаÑгийг ѳѳрчлѳх</translation> + </message> + <message> + <source>Edit sending address</source> + <translation>Явуулах хаÑгийг ѳѳрчлѳх</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book.</source> + <translation>Таны оруулÑан хаÑг "%1" нь хаÑгийн бүртгÑлд ѳмнѳ нь орÑон байна</translation> + </message> + <message> + <source>The entered address "%1" is not a valid Bitcoin address.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Түрүйвчийн цоожийг тайлж чадÑангүй</translation> + </message> + <message> + <source>New key generation failed.</source> + <translation>Ð¨Ð¸Ð½Ñ Ñ‚Ò¯Ð»Ñ…Ò¯Ò¯Ñ€ амжилттай гарÑангүй</translation> + </message> +</context> +<context> + <name>FreespaceChecker</name> + <message> + <source>A new data directory will be created.</source> + <translation type="unfinished"/> + </message> + <message> + <source>name</source> + <translation type="unfinished"/> + </message> + <message> + <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Path already exists, and is not a directory.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Cannot create data directory here.</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>HelpMessageDialog</name> + <message> + <source>Bitcoin Core - Command-line options</source> + <translation type="unfinished"/> + </message> + <message> + <source>Bitcoin Core</source> + <translation type="unfinished"/> + </message> + <message> + <source>version</source> + <translation>хувилбар</translation> + </message> + <message> + <source>Usage:</source> + <translation>Ð¥ÑÑ€ÑглÑÑ:</translation> + </message> + <message> + <source>command-line options</source> + <translation type="unfinished"/> + </message> + <message> + <source>UI options</source> + <translation type="unfinished"/> + </message> + <message> + <source>Set language, for example "de_DE" (default: system locale)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Start minimized</source> + <translation type="unfinished"/> + </message> + <message> + <source>Set SSL root certificates for payment request (default: -system-)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Show splash screen on startup (default: 1)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Choose data directory on startup (default: 0)</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>Intro</name> + <message> + <source>Welcome</source> + <translation type="unfinished"/> + </message> + <message> + <source>Welcome to Bitcoin Core.</source> + <translation type="unfinished"/> + </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"/> + </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"/> + </message> + <message> + <source>Use the default data directory</source> + <translation type="unfinished"/> + </message> + <message> + <source>Use a custom data directory:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Bitcoin</source> + <translation>Биткойн</translation> + </message> + <message> + <source>Error: Specified data directory "%1" can not be created.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error</source> + <translation>Ðлдаа</translation> + </message> + <message> + <source>GB of free space available</source> + <translation type="unfinished"/> + </message> + <message> + <source>(of %1GB needed)</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>OpenURIDialog</name> + <message> + <source>Open URI</source> + <translation type="unfinished"/> + </message> + <message> + <source>Open payment request from URI or file</source> + <translation type="unfinished"/> + </message> + <message> + <source>URI:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Select payment request file</source> + <translation type="unfinished"/> + </message> + <message> + <source>Select payment request file to open</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>OptionsDialog</name> + <message> + <source>Options</source> + <translation>Сонголтууд</translation> + </message> + <message> + <source>&Main</source> + <translation type="unfinished"/> + </message> + <message> + <source>Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Pay transaction &fee</source> + <translation type="unfinished"/> + </message> + <message> + <source>Automatically start Bitcoin after logging in to the system.</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Start Bitcoin on system login</source> + <translation type="unfinished"/> + </message> + <message> + <source>Size of &database cache</source> + <translation type="unfinished"/> + </message> + <message> + <source>MB</source> + <translation>МБ</translation> + </message> + <message> + <source>Number of script &verification threads</source> + <translation type="unfinished"/> + </message> + <message> + <source>Connect to the Bitcoin network through a SOCKS proxy.</source> + <translation>Биткойны ÑүлжÑÑÑ€Ò¯Ò¯ SOCKS прокÑигоор холбогдох.</translation> + </message> + <message> + <source>&Connect through SOCKS proxy (default proxy):</source> + <translation type="unfinished"/> + </message> + <message> + <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <translation>прокÑигийн IP хаÑг (жишÑÑ Ð½ÑŒ: 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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> + <source>Active command-line options that override above options:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Reset all client options to default.</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Reset Options</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Network</source> + <translation type="unfinished"/> + </message> + <message> + <source>(0 = auto, <0 = leave that many cores free)</source> + <translation type="unfinished"/> + </message> + <message> + <source>W&allet</source> + <translation type="unfinished"/> + </message> + <message> + <source>Expert</source> + <translation type="unfinished"/> + </message> + <message> + <source>Enable coin &control features</source> + <translation type="unfinished"/> + </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"/> + </message> + <message> + <source>&Spend unconfirmed change</source> + <translation type="unfinished"/> + </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> + <translation type="unfinished"/> + </message> + <message> + <source>Map port using &UPnP</source> + <translation type="unfinished"/> + </message> + <message> + <source>Proxy &IP:</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Port:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Port of the proxy (e.g. 9050)</source> + <translation type="unfinished"/> + </message> + <message> + <source>SOCKS &Version:</source> + <translation type="unfinished"/> + </message> + <message> + <source>SOCKS version of the proxy (e.g. 5)</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Window</source> + <translation type="unfinished"/> + </message> + <message> + <source>Show only a tray icon after minimizing the window.</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Minimize to the tray instead of the taskbar</source> + <translation type="unfinished"/> + </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 type="unfinished"/> + </message> + <message> + <source>M&inimize on close</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Display</source> + <translation type="unfinished"/> + </message> + <message> + <source>User Interface &language:</source> + <translation type="unfinished"/> + </message> + <message> + <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin.</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Unit to show amounts in:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Choose the default subdivision unit to show in the interface and when sending coins.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Whether to show Bitcoin addresses in the transaction list or not.</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Display addresses in transaction list</source> + <translation type="unfinished"/> + </message> + <message> + <source>Whether to show coin control features or not.</source> + <translation type="unfinished"/> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"/> + </message> + <message> + <source>default</source> + <translation type="unfinished"/> + </message> + <message> + <source>none</source> + <translation type="unfinished"/> + </message> + <message> + <source>Confirm options reset</source> + <translation type="unfinished"/> + </message> + <message> + <source>Client restart required to activate changes.</source> + <translation>Ѳѳрчлѳлтүүдийг идÑвхижүүлхийн тулд клиентийг ахин ÑхлүүлÑÑ… шаардлагтай</translation> + </message> + <message> + <source>Client will be shutdown, do you want to proceed?</source> + <translation>Клиент унтрах гÑж байна, Ñг унтраах уу?</translation> + </message> + <message> + <source>This change would require a client restart.</source> + <translation>ÐÐ½Ñ Ñ³Ñ³Ñ€Ñ‡Ð»Ñ³Ð»Ñ‚Ð¸Ð¹Ð³ оруулахын тулд кли1нт програмыг ахин ÑхлүүлÑÑ… шаардлагтай</translation> + </message> + <message> + <source>The supplied proxy address is invalid.</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>OverviewPage</name> + <message> + <source>Form</source> + <translation type="unfinished"/> + </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> + <translation type="unfinished"/> + </message> + <message> + <source>Wallet</source> + <translation>Түрүйвч</translation> + </message> + <message> + <source>Available:</source> + <translation>Ð¥ÑÑ€ÑглÑж болох Ñ…ÑмжÑÑ:</translation> + </message> + <message> + <source>Your current spendable balance</source> + <translation type="unfinished"/> + </message> + <message> + <source>Pending:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> + <translation type="unfinished"/> + </message> + <message> + <source>Immature:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Mined balance that has not yet matured</source> + <translation type="unfinished"/> + </message> + <message> + <source>Total:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Your current total balance</source> + <translation type="unfinished"/> + </message> + <message> + <source><b>Recent transactions</b></source> + <translation><b>Сүүлд хийгдÑÑн гүйлгÑÑнүүд</b></translation> + </message> + <message> + <source>out of sync</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>PaymentServer</name> + <message> + <source>URI handling</source> + <translation type="unfinished"/> + </message> + <message> + <source>URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Requested payment amount of %1 is too small (considered dust).</source> + <translation type="unfinished"/> + </message> + <message> + <source>Payment request error</source> + <translation type="unfinished"/> + </message> + <message> + <source>Cannot start bitcoin: click-to-pay handler</source> + <translation type="unfinished"/> + </message> + <message> + <source>Net manager warning</source> + <translation type="unfinished"/> + </message> + <message> + <source>Your active proxy doesn't support SOCKS5, which is required for payment requests via proxy.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Payment request fetch URL is invalid: %1</source> + <translation type="unfinished"/> + </message> + <message> + <source>Payment request file handling</source> + <translation type="unfinished"/> + </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"/> + </message> + <message> + <source>Unverified payment requests to custom payment scripts are unsupported.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Refund from %1</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error communicating with %1: %2</source> + <translation type="unfinished"/> + </message> + <message> + <source>Payment request can not be parsed or processed!</source> + <translation type="unfinished"/> + </message> + <message> + <source>Bad response from server %1</source> + <translation type="unfinished"/> + </message> + <message> + <source>Payment acknowledged</source> + <translation type="unfinished"/> + </message> + <message> + <source>Network request error</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>QObject</name> + <message> + <source>Bitcoin</source> + <translation>Биткойн</translation> + </message> + <message> + <source>Error: Specified data directory "%1" does not exist.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error: Invalid combination of -regtest and -testnet.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>QRImageWidget</name> + <message> + <source>&Save Image...</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Copy Image</source> + <translation type="unfinished"/> + </message> + <message> + <source>Save QR Code</source> + <translation type="unfinished"/> + </message> + <message> + <source>PNG Image (*.png)</source> + <translation>PNG форматын зураг (*.png)</translation> + </message> +</context> +<context> + <name>RPCConsole</name> + <message> + <source>Client name</source> + <translation>Клиентийн нÑÑ€</translation> + </message> + <message> + <source>N/A</source> + <translation>Ðлга Байна</translation> + </message> + <message> + <source>Client version</source> + <translation>Клиентийн хувилбар</translation> + </message> + <message> + <source>&Information</source> + <translation>&ÐœÑдÑÑллÑл</translation> + </message> + <message> + <source>Debug window</source> + <translation type="unfinished"/> + </message> + <message> + <source>General</source> + <translation>Ерѳнхий</translation> + </message> + <message> + <source>Using OpenSSL version</source> + <translation type="unfinished"/> + </message> + <message> + <source>Startup time</source> + <translation type="unfinished"/> + </message> + <message> + <source>Network</source> + <translation>СүлжÑÑ</translation> + </message> + <message> + <source>Name</source> + <translation>ÐÑÑ€</translation> + </message> + <message> + <source>Number of connections</source> + <translation>Холболтын тоо</translation> + </message> + <message> + <source>Block chain</source> + <translation>Блокийн цуваа</translation> + </message> + <message> + <source>Current number of blocks</source> + <translation>Одоогийн блокийн тоо</translation> + </message> + <message> + <source>Estimated total blocks</source> + <translation>Ðийт блокийн барагцаа</translation> + </message> + <message> + <source>Last block time</source> + <translation>Сүүлийн блокийн хугацаа</translation> + </message> + <message> + <source>&Open</source> + <translation>&ÐÑÑÑ…</translation> + </message> + <message> + <source>&Console</source> + <translation>&КонÑол</translation> + </message> + <message> + <source>&Network Traffic</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Clear</source> + <translation type="unfinished"/> + </message> + <message> + <source>Totals</source> + <translation type="unfinished"/> + </message> + <message> + <source>In:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Out:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Build date</source> + <translation type="unfinished"/> + </message> + <message> + <source>Debug log file</source> + <translation type="unfinished"/> + </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 type="unfinished"/> + </message> + <message> + <source>Clear console</source> + <translation>КонÑолыг цÑвÑрлÑÑ…</translation> + </message> + <message> + <source>Welcome to the Bitcoin RPC console.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Type <b>help</b> for an overview of available commands.</source> + <translation type="unfinished"/> + </message> + <message> + <source>%1 B</source> + <translation type="unfinished"/> + </message> + <message> + <source>%1 KB</source> + <translation type="unfinished"/> + </message> + <message> + <source>%1 MB</source> + <translation type="unfinished"/> + </message> + <message> + <source>%1 GB</source> + <translation type="unfinished"/> + </message> + <message> + <source>%1 m</source> + <translation type="unfinished"/> + </message> + <message> + <source>%1 h</source> + <translation type="unfinished"/> + </message> + <message> + <source>%1 h %2 m</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>ReceiveCoinsDialog</name> + <message> + <source>&Amount:</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Label:</source> + <translation>&Шошго:</translation> + </message> + <message> + <source>&Message:</source> + <translation type="unfinished"/> + </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"/> + </message> + <message> + <source>R&euse an existing receiving address (not recommended)</source> + <translation type="unfinished"/> + </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"/> + </message> + <message> + <source>An optional label to associate with the new receiving address.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Use this form to request payments. All fields are <b>optional</b>.</source> + <translation type="unfinished"/> + </message> + <message> + <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Clear</source> + <translation type="unfinished"/> + </message> + <message> + <source>Requested payments history</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Request payment</source> + <translation type="unfinished"/> + </message> + <message> + <source>Show the selected request (does the same as double clicking an entry)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Show</source> + <translation>Харуул</translation> + </message> + <message> + <source>Remove the selected entries from the list</source> + <translation>СонгогдÑон ѳгѳгдлүүдийг уÑтгах</translation> + </message> + <message> + <source>Remove</source> + <translation>УÑтгах</translation> + </message> + <message> + <source>Copy label</source> + <translation>Шошгыг Ñанах</translation> + </message> + <message> + <source>Copy message</source> + <translation>ЗурваÑыг Ñанах</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Ð¥ÑмжÑÑг Ñанах</translation> + </message> +</context> +<context> + <name>ReceiveRequestDialog</name> + <message> + <source>QR Code</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy &URI</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy &Address</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Save Image...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Request payment to %1</source> + <translation type="unfinished"/> + </message> + <message> + <source>Payment information</source> + <translation type="unfinished"/> + </message> + <message> + <source>URI</source> + <translation type="unfinished"/> + </message> + <message> + <source>Address</source> + <translation>ХаÑг</translation> + </message> + <message> + <source>Amount</source> + <translation>Ð¥ÑмжÑÑ</translation> + </message> + <message> + <source>Label</source> + <translation>Шошго</translation> + </message> + <message> + <source>Message</source> + <translation>ЗурваÑ</translation> + </message> + <message> + <source>Resulting URI too long, try to reduce the text for label / message.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error encoding URI into QR Code.</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>RecentRequestsTableModel</name> + <message> + <source>Date</source> + <translation>Огноо</translation> + </message> + <message> + <source>Label</source> + <translation>Шошго</translation> + </message> + <message> + <source>Message</source> + <translation>ЗурваÑ</translation> + </message> + <message> + <source>Amount</source> + <translation>Ð¥ÑмжÑÑ</translation> + </message> + <message> + <source>(no label)</source> + <translation>(шошго алга)</translation> + </message> + <message> + <source>(no message)</source> + <translation>(Ð·ÑƒÑ€Ð²Ð°Ñ Ð°Ð»Ð³Ð°)</translation> + </message> + <message> + <source>(no amount)</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>SendCoinsDialog</name> + <message> + <source>Send Coins</source> + <translation>Ð—Ð¾Ð¾Ñ Ñвуулах</translation> + </message> + <message> + <source>Coin Control Features</source> + <translation type="unfinished"/> + </message> + <message> + <source>Inputs...</source> + <translation type="unfinished"/> + </message> + <message> + <source>automatically selected</source> + <translation>автоматаар ÑонгогдÑон</translation> + </message> + <message> + <source>Insufficient funds!</source> + <translation>Таны данÑны үлдÑгдÑл хүрÑлцÑхгүй байна!</translation> + </message> + <message> + <source>Quantity:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Bytes:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Amount:</source> + <translation>Ð¥ÑмжÑÑ:</translation> + </message> + <message> + <source>Priority:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Fee:</source> + <translation>Тѳлбѳр:</translation> + </message> + <message> + <source>Low Output:</source> + <translation type="unfinished"/> + </message> + <message> + <source>After Fee:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Change:</source> + <translation type="unfinished"/> + </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"/> + </message> + <message> + <source>Custom change address</source> + <translation type="unfinished"/> + </message> + <message> + <source>Send to multiple recipients at once</source> + <translation>ÐÑгÑн зÑÑ€Ñг олон хүлÑÑн авагчруу Ñвуулах</translation> + </message> + <message> + <source>Add &Recipient</source> + <translation>&ХүлÑÑн авагчийг ÐÑмÑÑ…</translation> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Clear &All</source> + <translation>&Бүгдийг ЦÑвÑрлÑ</translation> + </message> + <message> + <source>Balance:</source> + <translation>БаланÑ:</translation> + </message> + <message> + <source>Confirm the send action</source> + <translation>Явуулах үйлдлийг баталгаажуулна уу</translation> + </message> + <message> + <source>S&end</source> + <translation>Яв&уул</translation> + </message> + <message> + <source>Confirm send coins</source> + <translation>Ð—Ð¾Ð¾Ñ Ñвуулахыг баталгаажуулна уу</translation> + </message> + <message> + <source>%1 to %2</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy quantity</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy amount</source> + <translation>Ð¥ÑмжÑÑг Ñанах</translation> + </message> + <message> + <source>Copy fee</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy after fee</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy bytes</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy priority</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy low output</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy change</source> + <translation>Ѳѳрчлѳлтийг Ñанах</translation> + </message> + <message> + <source>Total Amount %1 (= %2)</source> + <translation>Ðийт дүн %1 (= %2)</translation> + </message> + <message> + <source>or</source> + <translation>ÑÑвÑл</translation> + </message> + <message> + <source>The recipient address is not valid, please recheck.</source> + <translation type="unfinished"/> + </message> + <message> + <source>The amount to pay must be larger than 0.</source> + <translation>Тѳлѳх Ñ…ÑмжÑÑ 0.-Ð¾Ð¾Ñ Ð¸Ñ… байх Ñ‘Ñтой</translation> + </message> + <message> + <source>The amount exceeds your balance.</source> + <translation>ÐÐ½Ñ Ñ…ÑмжÑÑ Ñ‚Ð°Ð½Ñ‹ баланÑÐ°Ð°Ñ Ñ…ÑÑ‚ÑÑ€ÑÑн байна.</translation> + </message> + <message> + <source>The total exceeds your balance when the %1 transaction fee is included.</source> + <translation>ГүйлгÑÑний тѳлбѳр %1-ийг тооцхоор нийт дүн нь таны баланÑÐ°Ð°Ñ Ñ…ÑÑ‚Ñ€ÑÑд байна.</translation> + </message> + <message> + <source>Duplicate address found, can only send to each address once per send operation.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Transaction creation failed!</source> + <translation type="unfinished"/> + </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"/> + </message> + <message> + <source>Warning: Invalid Bitcoin address</source> + <translation>Ðнхаар:Буруу Биткойны хаÑг байна</translation> + </message> + <message> + <source>(no label)</source> + <translation>(шошгогүй)</translation> + </message> + <message> + <source>Warning: Unknown change address</source> + <translation type="unfinished"/> + </message> + <message> + <source>Are you sure you want to send?</source> + <translation type="unfinished"/> + </message> + <message> + <source>added as transaction fee</source> + <translation type="unfinished"/> + </message> + <message> + <source>Payment request expired</source> + <translation type="unfinished"/> + </message> + <message> + <source>Invalid payment address %1</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>SendCoinsEntry</name> + <message> + <source>A&mount:</source> + <translation>Дүн:</translation> + </message> + <message> + <source>Pay &To:</source> + <translation>Тѳлѳх &хаÑг:</translation> + </message> + <message> + <source>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Enter a label for this address to add it to your address book</source> + <translation>ÐÐ½Ñ Ñ…Ð°Ñгийг ѳѳрийн бүртгÑлдÑÑ Ð°Ð²Ð°Ñ…Ñ‹Ð½ тулд шошго оруул</translation> + </message> + <message> + <source>&Label:</source> + <translation>&Шошго:</translation> + </message> + <message> + <source>Choose previously used address</source> + <translation type="unfinished"/> + </message> + <message> + <source>This is a normal payment.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Alt+A</source> + <translation>Alt+A</translation> + </message> + <message> + <source>Paste address from clipboard</source> + <translation>КопидÑон хаÑгийг буулгах</translation> + </message> + <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> + <source>Remove this entry</source> + <translation type="unfinished"/> + </message> + <message> + <source>Message:</source> + <translation>ЗурваÑ:</translation> + </message> + <message> + <source>This is a verified payment request.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Enter a label for this address to add it to the list of used addresses</source> + <translation type="unfinished"/> + </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"/> + </message> + <message> + <source>This is an unverified payment request.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Pay To:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Memo:</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>ShutdownWindow</name> + <message> + <source>Bitcoin Core is shutting down...</source> + <translation>Биткойны цѳм хаагдаж байна...</translation> + </message> + <message> + <source>Do not shut down the computer until this window disappears.</source> + <translation>ÐÐ½Ñ Ñ†Ð¾Ð½Ñ…Ñ‹Ð³ хаагдтал компьютерÑÑ Ð±Ò¯Ò¯ унтраагаарай</translation> + </message> +</context> +<context> + <name>SignVerifyMessageDialog</name> + <message> + <source>Signatures - Sign / Verify a Message</source> + <translation type="unfinished"/> + </message> + <message> + <source>&Sign Message</source> + <translation type="unfinished"/> + </message> + <message> + <source>You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> + <translation type="unfinished"/> + </message> + <message> + <source>The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Choose previously used address</source> + <translation type="unfinished"/> + </message> + <message> + <source>Alt+A</source> + <translation>Alt+A</translation> + </message> + <message> + <source>Paste address from clipboard</source> + <translation>КопидÑон хаÑгийг буулгах</translation> + </message> + <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> + <source>Enter the message you want to sign here</source> + <translation type="unfinished"/> + </message> + <message> + <source>Signature</source> + <translation type="unfinished"/> + </message> + <message> + <source>Copy the current signature to the system clipboard</source> + <translation type="unfinished"/> + </message> + <message> + <source>Sign the message to prove you own this Bitcoin address</source> + <translation type="unfinished"/> + </message> + <message> + <source>Sign &Message</source> + <translation type="unfinished"/> + </message> + <message> + <source>Reset all sign message fields</source> + <translation type="unfinished"/> + </message> + <message> + <source>Clear &All</source> + <translation>&Бүгдийг ЦÑвÑрлÑ</translation> + </message> + <message> + <source>&Verify Message</source> + <translation type="unfinished"/> + </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 type="unfinished"/> + </message> + <message> + <source>The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> + <translation type="unfinished"/> + </message> + <message> + <source>Verify &Message</source> + <translation type="unfinished"/> + </message> + <message> + <source>Reset all verify message fields</source> + <translation type="unfinished"/> + </message> + <message> + <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Click "Sign Message" to generate signature</source> + <translation type="unfinished"/> + </message> + <message> + <source>The entered address is invalid.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Please check the address and try again.</source> + <translation type="unfinished"/> + </message> + <message> + <source>The entered address does not refer to a key.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Wallet unlock was cancelled.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Private key for the entered address is not available.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Message signing failed.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Message signed.</source> + <translation type="unfinished"/> + </message> + <message> + <source>The signature could not be decoded.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Please check the signature and try again.</source> + <translation type="unfinished"/> + </message> + <message> + <source>The signature did not match the message digest.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Message verification failed.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Message verified.</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>SplashScreen</name> + <message> + <source>Bitcoin Core</source> + <translation type="unfinished"/> + </message> + <message> + <source>The Bitcoin Core developers</source> + <translation type="unfinished"/> + </message> + <message> + <source>[testnet]</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>TrafficGraphWidget</name> + <message> + <source>KB/s</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>TransactionDesc</name> + <message> + <source>Open until %1</source> + <translation>%1 хүртÑл нÑÑлттÑй</translation> + </message> + <message> + <source>conflicted</source> + <translation>зѳрчилдлѳѳ</translation> + </message> + <message> + <source>%1/offline</source> + <translation type="unfinished"/> + </message> + <message> + <source>%1/unconfirmed</source> + <translation>%1/баталгаажаагүй</translation> + </message> + <message> + <source>%1 confirmations</source> + <translation>%1 баталгаажилтууд</translation> + </message> + <message> + <source>Status</source> + <translation type="unfinished"/> + </message> + <message numerus="yes"> + <source>, broadcast through %n node(s)</source> + <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> + </message> + <message> + <source>Date</source> + <translation>Огноо</translation> + </message> + <message> + <source>Source</source> + <translation type="unfinished"/> + </message> + <message> + <source>Generated</source> + <translation type="unfinished"/> + </message> + <message> + <source>From</source> + <translation type="unfinished"/> + </message> + <message> + <source>To</source> + <translation type="unfinished"/> + </message> + <message> + <source>own address</source> + <translation type="unfinished"/> + </message> + <message> + <source>label</source> + <translation type="unfinished"/> + </message> + <message> + <source>Credit</source> + <translation type="unfinished"/> + </message> + <message numerus="yes"> + <source>matures in %n more block(s)</source> + <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> + </message> + <message> + <source>not accepted</source> + <translation type="unfinished"/> + </message> + <message> + <source>Debit</source> + <translation type="unfinished"/> + </message> + <message> + <source>Transaction fee</source> + <translation type="unfinished"/> + </message> + <message> + <source>Net amount</source> + <translation type="unfinished"/> + </message> + <message> + <source>Message</source> + <translation>ЗурваÑ</translation> + </message> + <message> + <source>Comment</source> + <translation type="unfinished"/> + </message> + <message> + <source>Transaction ID</source> + <translation type="unfinished"/> + </message> + <message> + <source>Merchant</source> + <translation type="unfinished"/> + </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 "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Debug information</source> + <translation type="unfinished"/> + </message> + <message> + <source>Transaction</source> + <translation type="unfinished"/> + </message> + <message> + <source>Inputs</source> + <translation type="unfinished"/> + </message> + <message> + <source>Amount</source> + <translation>Ð¥ÑмжÑÑ</translation> + </message> + <message> + <source>true</source> + <translation type="unfinished"/> + </message> + <message> + <source>false</source> + <translation type="unfinished"/> + </message> + <message> + <source>, has not been successfully broadcast yet</source> + <translation>, хараахан амжилттай цацагдаагүй байна</translation> + </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> + </message> + <message> + <source>unknown</source> + <translation>үл мÑдÑгдÑÑ…</translation> + </message> +</context> +<context> + <name>TransactionDescDialog</name> + <message> + <source>Transaction details</source> + <translation>ГүйлгÑÑний мÑдÑÑллÑл</translation> + </message> + <message> + <source>This pane shows a detailed description of the transaction</source> + <translation>ГүйлгÑÑний дÑлгÑÑ€Ñнгүйг ÑÐ½Ñ Ð±Ð¸Ñ‡Ð¸Ð» цонх харуулж байна</translation> + </message> +</context> +<context> + <name>TransactionTableModel</name> + <message> + <source>Date</source> + <translation>Огноо</translation> + </message> + <message> + <source>Type</source> + <translation>Тѳрѳл</translation> + </message> + <message> + <source>Address</source> + <translation>ХаÑг</translation> + </message> + <message> + <source>Amount</source> + <translation>Ð¥ÑмжÑÑ</translation> + </message> + <message> + <source>Immature (%1 confirmations, will be available after %2)</source> + <translation type="unfinished"/> + </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> + </message> + <message> + <source>Open until %1</source> + <translation>%1 хүртÑл нÑÑлттÑй</translation> + </message> + <message> + <source>Confirmed (%1 confirmations)</source> + <translation>Баталгаажлаа (%1 баталгаажилт)</translation> + </message> + <message> + <source>This block was not received by any other nodes and will probably not be accepted!</source> + <translation>ÐÐ½Ñ Ð±Ð»Ð¾ÐºÐ¸Ð¹Ð³ аль ч нод хүлÑÑн авÑангүй ба ер нь зѳвшѳѳрѳгдѳхгүй байж мÑднÑ!</translation> + </message> + <message> + <source>Generated but not accepted</source> + <translation>Ò®Ò¯ÑгÑгдÑÑн гÑхдÑÑ Ñ…Ò¯Ð»ÑÑн авагдаагүй</translation> + </message> + <message> + <source>Offline</source> + <translation type="unfinished"/> + </message> + <message> + <source>Unconfirmed</source> + <translation>Баталгаажаагүй</translation> + </message> + <message> + <source>Confirming (%1 of %2 recommended confirmations)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Conflicted</source> + <translation>Зѳрчилдлѳѳ</translation> + </message> + <message> + <source>Received with</source> + <translation>ХүлÑÑн авÑан хаÑг</translation> + </message> + <message> + <source>Received from</source> + <translation>ХүлÑÑн авагдÑан хаÑг</translation> + </message> + <message> + <source>Sent to</source> + <translation>ЯвуулÑан хаÑг</translation> + </message> + <message> + <source>Payment to yourself</source> + <translation>ѲѳрлүүгÑÑ Ñ…Ð¸Ð¹ÑÑн тѳлбѳр</translation> + </message> + <message> + <source>Mined</source> + <translation>ОлборлогдÑон</translation> + </message> + <message> + <source>(n/a)</source> + <translation>(алга байна)</translation> + </message> + <message> + <source>Transaction status. Hover over this field to show number of confirmations.</source> + <translation>ГүйлгÑÑний байдал. Ðнд хулганыг авчирч баталгаажуулалтын тоог харна уу.</translation> + </message> + <message> + <source>Date and time that the transaction was received.</source> + <translation>ГүйлгÑÑг хүлÑÑн авÑан огноо ба цаг.</translation> + </message> + <message> + <source>Type of transaction.</source> + <translation>ГүйлгÑÑний тѳрѳл</translation> + </message> + <message> + <source>Destination address of transaction.</source> + <translation>ГүйлгÑÑг хүлÑÑн авах хаÑг</translation> + </message> + <message> + <source>Amount removed from or added to balance.</source> + <translation>БаланÑÐ°Ð°Ñ Ð°Ð²Ð°Ð³Ð´Ñан болон нÑмÑгдÑÑн Ñ…ÑмжÑÑ.</translation> + </message> +</context> +<context> + <name>TransactionView</name> + <message> + <source>All</source> + <translation>Бүгд</translation> + </message> + <message> + <source>Today</source> + <translation>Ѳнѳѳдѳр</translation> + </message> + <message> + <source>This week</source> + <translation>ÐÐ½Ñ Ð´Ð¾Ð»Ð¾Ð¾ хоног</translation> + </message> + <message> + <source>This month</source> + <translation>ÐÐ½Ñ Ñар</translation> + </message> + <message> + <source>Last month</source> + <translation>ѲнгѳрÑѳн Ñар</translation> + </message> + <message> + <source>This year</source> + <translation>ÐÐ½Ñ Ð¶Ð¸Ð»</translation> + </message> + <message> + <source>Range...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Received with</source> + <translation>ХүлÑÑн авÑан хаÑг</translation> + </message> + <message> + <source>Sent to</source> + <translation>ЯвуулÑан хаÑг</translation> + </message> + <message> + <source>To yourself</source> + <translation>ѲѳрлүүгÑÑ</translation> + </message> + <message> + <source>Mined</source> + <translation>ОлборлогдÑон</translation> + </message> + <message> + <source>Other</source> + <translation>БуÑад</translation> + </message> + <message> + <source>Enter address or label to search</source> + <translation>Хайлт хийхийн тулд хаÑг ÑÑвÑл шошгыг оруул</translation> + </message> + <message> + <source>Min amount</source> + <translation>Хамгийн бага Ñ…ÑмжÑÑ</translation> + </message> + <message> + <source>Copy address</source> + <translation>ХаÑгийг Ñанах</translation> + </message> + <message> + <source>Copy label</source> + <translation>Шошгыг Ñанах</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Ð¥ÑмжÑÑг Ñанах</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation type="unfinished"/> + </message> + <message> + <source>Edit label</source> + <translation>Шошгыг ѳѳрчлѳх</translation> + </message> + <message> + <source>Show transaction details</source> + <translation>ГүйлгÑÑний дÑлгÑÑ€Ñнгүйг харуул</translation> + </message> + <message> + <source>Export Transaction History</source> + <translation type="unfinished"/> + </message> + <message> + <source>Exporting Failed</source> + <translation type="unfinished"/> + </message> + <message> + <source>There was an error trying to save the transaction history to %1.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Exporting Successful</source> + <translation type="unfinished"/> + </message> + <message> + <source>The transaction history was successfully saved to %1.</source> + <translation>ГүйлгÑÑнүй түүхийг %1-д амжилттай хадгаллаа.</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>ТаÑлалаар туÑгаарлагдÑан Ñ…Ò¯ÑнÑгтÑн файл (.csv)</translation> + </message> + <message> + <source>Confirmed</source> + <translation>Баталгаажлаа</translation> + </message> + <message> + <source>Date</source> + <translation>Огноо</translation> + </message> + <message> + <source>Type</source> + <translation>Тѳрѳл</translation> + </message> + <message> + <source>Label</source> + <translation>Шошго</translation> + </message> + <message> + <source>Address</source> + <translation>ХаÑг</translation> + </message> + <message> + <source>Amount</source> + <translation>Ð¥ÑмжÑÑ</translation> + </message> + <message> + <source>ID</source> + <translation>Тодорхойлолт</translation> + </message> + <message> + <source>Range:</source> + <translation type="unfinished"/> + </message> + <message> + <source>to</source> + <translation>-Ñ€Ò¯Ò¯/руу</translation> + </message> +</context> +<context> + <name>WalletFrame</name> + <message> + <source>No wallet has been loaded.</source> + <translation>Ямар ч түрүйвч ачааллагдÑангүй.</translation> + </message> +</context> +<context> + <name>WalletModel</name> + <message> + <source>Send Coins</source> + <translation>Ð—Ð¾Ð¾Ñ Ñвуулах</translation> + </message> +</context> +<context> + <name>WalletView</name> + <message> + <source>&Export</source> + <translation type="unfinished"/> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation type="unfinished"/> + </message> + <message> + <source>Backup Wallet</source> + <translation type="unfinished"/> + </message> + <message> + <source>Wallet Data (*.dat)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Backup Failed</source> + <translation type="unfinished"/> + </message> + <message> + <source>There was an error trying to save the wallet data to %1.</source> + <translation type="unfinished"/> + </message> + <message> + <source>The wallet data was successfully saved to %1.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Backup Successful</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>bitcoin-core</name> + <message> + <source>Usage:</source> + <translation>Ð¥ÑÑ€ÑглÑÑ:</translation> + </message> + <message> + <source>List commands</source> + <translation>Үйлдлүүдийг жагÑаах</translation> + </message> + <message> + <source>Get help for a command</source> + <translation>ҮйлдÑлд туÑлалцаа авах</translation> + </message> + <message> + <source>Options:</source> + <translation>Сонголтууд:</translation> + </message> + <message> + <source>Specify configuration file (default: bitcoin.conf)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Specify pid file (default: bitcoind.pid)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Specify data directory</source> + <translation type="unfinished"/> + </message> + <message> + <source>Listen for connections on <port> (default: 8333 or testnet: 18333)</source> + <translation><port> дÑÑрх холболтуудыг чагна (ѳгѳгдмѳл: 8333 ÑÑвÑл testnet: 18333)</translation> + </message> + <message> + <source>Maintain at most <n> connections to peers (default: 125)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Connect to a node to retrieve peer addresses, and disconnect</source> + <translation type="unfinished"/> + </message> + <message> + <source>Specify your own public address</source> + <translation type="unfinished"/> + </message> + <message> + <source>Threshold for disconnecting misbehaving peers (default: 100)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source> + <translation type="unfinished"/> + </message> + <message> + <source>An error occurred while setting up the RPC port %u for listening on IPv4: %s</source> + <translation type="unfinished"/> + </message> + <message> + <source>Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Accept command line and JSON-RPC commands</source> + <translation type="unfinished"/> + </message> + <message> + <source>Bitcoin Core RPC client version</source> + <translation type="unfinished"/> + </message> + <message> + <source>Run in the background as a daemon and accept commands</source> + <translation type="unfinished"/> + </message> + <message> + <source>Use the test network</source> + <translation type="unfinished"/> + </message> + <message> + <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source> + <translation type="unfinished"/> + </message> + <message> + <source>%s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=bitcoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com +</source> + <translation type="unfinished"/> + </message> + <message> + <source>Acceptable ciphers (default: TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH)</source> + <translation type="unfinished"/> + </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"/> + </message> + <message> + <source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source> + <translation type="unfinished"/> + </message> + <message> + <source>Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:15)</source> + <translation type="unfinished"/> + </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"/> + </message> + <message> + <source>Enter regression test mode, which uses a special chain in which blocks can be solved instantly.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error: Listening for incoming connections failed (listen returned error %d)</source> + <translation type="unfinished"/> + </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"/> + </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 type="unfinished"/> + </message> + <message> + <source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Fees smaller than this are considered zero fee (for transaction creation) (default:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Flush database activity from memory pool to disk log every <n> megabytes (default: 100)</source> + <translation type="unfinished"/> + </message> + <message> + <source>How thorough the block verification of -checkblocks is (0-4, default: 3)</source> + <translation type="unfinished"/> + </message> + <message> + <source>In this mode -genproclimit controls how many blocks are generated immediately.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Set the processor limit for when generation is on (-1 = unlimited, default: -1)</source> + <translation type="unfinished"/> + </message> + <message> + <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> + <translation type="unfinished"/> + </message> + <message> + <source>Unable to bind to %s on this computer. Bitcoin Core is probably already running.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin will not work properly.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> + <translation type="unfinished"/> + </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"/> + </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> + <translation type="unfinished"/> + </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 type="unfinished"/> + </message> + <message> + <source>(default: 1)</source> + <translation type="unfinished"/> + </message> + <message> + <source>(default: wallet.dat)</source> + <translation type="unfinished"/> + </message> + <message> + <source><category> can be:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Attempt to recover private keys from a corrupt wallet.dat</source> + <translation type="unfinished"/> + </message> + <message> + <source>Bitcoin Core Daemon</source> + <translation type="unfinished"/> + </message> + <message> + <source>Block creation options:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Clear list of wallet transactions (diagnostic tool; implies -rescan)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Connect only to the specified node(s)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Connect through SOCKS proxy</source> + <translation>SOCKS прокÑигоор холбогдох</translation> + </message> + <message> + <source>Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Connection options:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Corrupted block database detected</source> + <translation type="unfinished"/> + </message> + <message> + <source>Debugging/Testing options:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Disable safemode, override a real safe mode event (default: 0)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Discover own IP address (default: 1 when listening and no -externalip)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Do not load the wallet and disable wallet RPC calls</source> + <translation type="unfinished"/> + </message> + <message> + <source>Do you want to rebuild the block database now?</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error initializing block database</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error initializing wallet database environment %s!</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error loading block database</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error opening block database</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error: Disk space is low!</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error: Wallet locked, unable to create transaction!</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error: system error: </source> + <translation type="unfinished"/> + </message> + <message> + <source>Failed to listen on any port. Use -listen=0 if you want this.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Failed to read block info</source> + <translation type="unfinished"/> + </message> + <message> + <source>Failed to read block</source> + <translation type="unfinished"/> + </message> + <message> + <source>Failed to sync block index</source> + <translation type="unfinished"/> + </message> + <message> + <source>Failed to write block index</source> + <translation type="unfinished"/> + </message> + <message> + <source>Failed to write block info</source> + <translation type="unfinished"/> + </message> + <message> + <source>Failed to write block</source> + <translation type="unfinished"/> + </message> + <message> + <source>Failed to write file info</source> + <translation type="unfinished"/> + </message> + <message> + <source>Failed to write to coin database</source> + <translation type="unfinished"/> + </message> + <message> + <source>Failed to write transaction index</source> + <translation type="unfinished"/> + </message> + <message> + <source>Failed to write undo data</source> + <translation type="unfinished"/> + </message> + <message> + <source>Fee per kB to add to transactions you send</source> + <translation type="unfinished"/> + </message> + <message> + <source>Fees smaller than this are considered zero fee (for relaying) (default:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Find peers using DNS lookup (default: 1 unless -connect)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Force safe mode (default: 0)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Generate coins (default: 0)</source> + <translation type="unfinished"/> + </message> + <message> + <source>How many blocks to check at startup (default: 288, 0 = all)</source> + <translation type="unfinished"/> + </message> + <message> + <source>If <category> is not supplied, output all debugging information.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Importing...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Incorrect or no genesis block found. Wrong datadir for network?</source> + <translation type="unfinished"/> + </message> + <message> + <source>Invalid -onion address: '%s'</source> + <translation type="unfinished"/> + </message> + <message> + <source>Not enough file descriptors available.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Prepend debug output with timestamp (default: 1)</source> + <translation type="unfinished"/> + </message> + <message> + <source>RPC client options:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Rebuild block chain index from current blk000??.dat files</source> + <translation type="unfinished"/> + </message> + <message> + <source>Select SOCKS version for -proxy (4 or 5, default: 5)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Set database cache size in megabytes (%d to %d, default: %d)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Set maximum block size in bytes (default: %d)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Set the number of threads to service RPC calls (default: 4)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Specify wallet file (within data directory)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Spend unconfirmed change when sending transactions (default: 1)</source> + <translation type="unfinished"/> + </message> + <message> + <source>This is intended for regression testing tools and app development.</source> + <translation type="unfinished"/> + </message> + <message> + <source>Usage (deprecated, use bitcoin-cli):</source> + <translation type="unfinished"/> + </message> + <message> + <source>Verifying blocks...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Verifying wallet...</source> + <translation type="unfinished"/> + </message> + <message> + <source>Wait for RPC server to start</source> + <translation>RPC Ñерверийг ÑÑ…ÑлтÑл хүлÑÑ</translation> + </message> + <message> + <source>Wallet %s resides outside data directory %s</source> + <translation type="unfinished"/> + </message> + <message> + <source>Wallet options:</source> + <translation>Түрүйвчийн Ñонголтууд:</translation> + </message> + <message> + <source>Warning: Deprecated argument -debugnet ignored, use -debug=net</source> + <translation type="unfinished"/> + </message> + <message> + <source>You need to rebuild the database using -reindex to change -txindex</source> + <translation type="unfinished"/> + </message> + <message> + <source>Imports blocks from external blk000??.dat file</source> + <translation type="unfinished"/> + </message> + <message> + <source>Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running.</source> + <translation type="unfinished"/> + </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"/> + </message> + <message> + <source>Output debugging information (default: 0, supplying <category> is optional)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Information</source> + <translation type="unfinished"/> + </message> + <message> + <source>Invalid amount for -minrelaytxfee=<amount>: '%s'</source> + <translation type="unfinished"/> + </message> + <message> + <source>Invalid amount for -mintxfee=<amount>: '%s'</source> + <translation type="unfinished"/> + </message> + <message> + <source>Limit size of signature cache to <n> entries (default: 50000)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Log transaction priority and fee per kB when mining blocks (default: 0)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Maintain a full transaction index (default: 0)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Only accept block chain matching built-in checkpoints (default: 1)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Only connect to nodes in network <net> (IPv4, IPv6 or Tor)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Print block on startup, if found in block index</source> + <translation type="unfinished"/> + </message> + <message> + <source>Print block tree on startup (default: 0)</source> + <translation type="unfinished"/> + </message> + <message> + <source>RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source> + <translation type="unfinished"/> + </message> + <message> + <source>RPC server options:</source> + <translation type="unfinished"/> + </message> + <message> + <source>Randomly drop 1 of every <n> network messages</source> + <translation type="unfinished"/> + </message> + <message> + <source>Randomly fuzz 1 of every <n> network messages</source> + <translation type="unfinished"/> + </message> + <message> + <source>Run a thread to flush wallet periodically (default: 1)</source> + <translation type="unfinished"/> + </message> + <message> + <source>SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Send command to Bitcoin Core</source> + <translation type="unfinished"/> + </message> + <message> + <source>Send trace/debug info to console instead of debug.log file</source> + <translation type="unfinished"/> + </message> + <message> + <source>Set minimum block size in bytes (default: 0)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Sets the DB_PRIVATE flag in the wallet db environment (default: 1)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Show all debugging options (usage: --help -help-debug)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Show benchmark information (default: 0)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Shrink debug.log file on client startup (default: 1 when no -debug)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Signing transaction failed</source> + <translation type="unfinished"/> + </message> + <message> + <source>Specify connection timeout in milliseconds (default: 5000)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Start Bitcoin Core Daemon</source> + <translation type="unfinished"/> + </message> + <message> + <source>System error: </source> + <translation type="unfinished"/> + </message> + <message> + <source>Transaction amount too small</source> + <translation type="unfinished"/> + </message> + <message> + <source>Transaction amounts must be positive</source> + <translation type="unfinished"/> + </message> + <message> + <source>Transaction too large</source> + <translation type="unfinished"/> + </message> + <message> + <source>Use UPnP to map the listening port (default: 0)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Use UPnP to map the listening port (default: 1 when listening)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Username for JSON-RPC connections</source> + <translation type="unfinished"/> + </message> + <message> + <source>Warning</source> + <translation type="unfinished"/> + </message> + <message> + <source>Warning: This version is obsolete, upgrade required!</source> + <translation type="unfinished"/> + </message> + <message> + <source>Zapping all transactions from wallet...</source> + <translation type="unfinished"/> + </message> + <message> + <source>on startup</source> + <translation type="unfinished"/> + </message> + <message> + <source>version</source> + <translation>хувилбар</translation> + </message> + <message> + <source>wallet.dat corrupt, salvage failed</source> + <translation type="unfinished"/> + </message> + <message> + <source>Password for JSON-RPC connections</source> + <translation type="unfinished"/> + </message> + <message> + <source>Allow JSON-RPC connections from specified IP address</source> + <translation type="unfinished"/> + </message> + <message> + <source>Send commands to node running on <ip> (default: 127.0.0.1)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Upgrade wallet to latest format</source> + <translation>Түрүйвчийг хамгийн Ñүүлийн үеийн форматруу шинÑчлÑÑ…</translation> + </message> + <message> + <source>Set key pool size to <n> (default: 100)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Rescan the block chain for missing wallet transactions</source> + <translation type="unfinished"/> + </message> + <message> + <source>Use OpenSSL (https) for JSON-RPC connections</source> + <translation type="unfinished"/> + </message> + <message> + <source>Server certificate file (default: server.cert)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Server private key (default: server.pem)</source> + <translation type="unfinished"/> + </message> + <message> + <source>This help message</source> + <translation type="unfinished"/> + </message> + <message> + <source>Unable to bind to %s on this computer (bind returned error %d, %s)</source> + <translation type="unfinished"/> + </message> + <message> + <source>Allow DNS lookups for -addnode, -seednode and -connect</source> + <translation type="unfinished"/> + </message> + <message> + <source>Loading addresses...</source> + <translation>ХаÑгуудыг ачааллаж байна...</translation> + </message> + <message> + <source>Error loading wallet.dat: Wallet corrupted</source> + <translation>wallet.dat-ыг ачааллахад алдаа гарлаа: Түрүйвч ÑвдÑÑ€ÑÑн байна</translation> + </message> + <message> + <source>Error loading wallet.dat: Wallet requires newer version of Bitcoin</source> + <translation>wallet.dat-ыг ачааллахад алдаа гарлаа: Түрүйвч Биткойны ÑˆÐ¸Ð½Ñ Ñ…ÑƒÐ²Ð¸Ð»Ð±Ð°Ñ€Ñ‹Ð³ шаардаж байна</translation> + </message> + <message> + <source>Wallet needed to be rewritten: restart Bitcoin to complete</source> + <translation type="unfinished"/> + </message> + <message> + <source>Error loading wallet.dat</source> + <translation>wallet.dat-ыг ачааллахад алдаа гарлаа</translation> + </message> + <message> + <source>Invalid -proxy address: '%s'</source> + <translation>ÐдгÑÑÑ€ прокÑи хаÑгнууд буруу байна: '%s'</translation> + </message> + <message> + <source>Unknown network specified in -onlynet: '%s'</source> + <translation type="unfinished"/> + </message> + <message> + <source>Unknown -socks proxy version requested: %i</source> + <translation type="unfinished"/> + </message> + <message> + <source>Cannot resolve -bind address: '%s'</source> + <translation type="unfinished"/> + </message> + <message> + <source>Cannot resolve -externalip address: '%s'</source> + <translation type="unfinished"/> + </message> + <message> + <source>Invalid amount for -paytxfee=<amount>: '%s'</source> + <translation type="unfinished"/> + </message> + <message> + <source>Invalid amount</source> + <translation>Буруу Ñ…ÑмжÑÑ</translation> + </message> + <message> + <source>Insufficient funds</source> + <translation>Таны данÑны үлдÑгдÑл хүрÑлцÑхгүй байна</translation> + </message> + <message> + <source>Loading block index...</source> + <translation>Блокийн индекÑүүдийг ачааллаж байна...</translation> + </message> + <message> + <source>Add a node to connect to and attempt to keep the connection open</source> + <translation>Холболт хийхийн тулд мѳн холболтой онгорхой хадгалхын тулд ÑˆÐ¸Ð½Ñ Ð½Ð¾Ð´ нÑм</translation> + </message> + <message> + <source>Loading wallet...</source> + <translation>Түрүйвчийг ачааллаж байна...</translation> + </message> + <message> + <source>Cannot downgrade wallet</source> + <translation type="unfinished"/> + </message> + <message> + <source>Cannot write default address</source> + <translation type="unfinished"/> + </message> + <message> + <source>Rescanning...</source> + <translation>Ðхин уншиж байна...</translation> + </message> + <message> + <source>Done loading</source> + <translation>Ðчааллаж дууÑлаа</translation> + </message> + <message> + <source>To use the %s option</source> + <translation>%s Ñонголтыг ашиглахын тулд</translation> + </message> + <message> + <source>Error</source> + <translation>Ðлдаа</translation> + </message> + <message> + <source>You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions.</source> + <translation type="unfinished"/> + </message> +</context> +</TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_ms_MY.ts b/src/qt/locale/bitcoin_ms_MY.ts index 9835a2e19f..0f92a6d49f 100644 --- a/src/qt/locale/bitcoin_ms_MY.ts +++ b/src/qt/locale/bitcoin_ms_MY.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ms_MY" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ms_MY" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts index 078bad7edc..9e38c69c60 100644 --- a/src/qt/locale/bitcoin_nb.ts +++ b/src/qt/locale/bitcoin_nb.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="nb" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="nb" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -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> @@ -1048,6 +1048,14 @@ Adresse: %4 <translation>IP-adressen til proxyen (f.eks. 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>Tredjepart URLer (f. eks. en blokkutforsker) som dukker opp i transaksjonsfanen som kontekst meny elementer. %s i URLen er erstattet med transaksjonen sin hash. Flere URLer er separert av en vertikal linje |.</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>Tredjepart transaksjon URLer</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Aktive kommandolinjevalg som overstyrer valgene ovenfor:</translation> </message> @@ -1349,8 +1357,8 @@ Adresse: %4 <translation>Feil: Ugyldig kombinasjon av -regtest og -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> - <translation>Bitcoin Core har annÃ¥ ikke avsluttet pÃ¥ en sikker mÃ¥te...</translation> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>Bitcoin Core har ennÃ¥ ikke avsluttet pÃ¥ en sikker mÃ¥te...</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -1736,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> @@ -2722,7 +2730,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin Varsel" 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_nl.ts b/src/qt/locale/bitcoin_nl.ts index 0da46059b5..8cbbbdad7f 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="nl" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="nl" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1048,6 +1048,14 @@ Adres: %4 <translation>IP-adres van de proxy (bijv. 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>Derde partijen URL's (bijvoorbeeld block explorer) dat in de transacties tab verschijnen als contextmenu elementen. %s in de URL is vervangen door transactie hash. Verscheidene URL's zijn gescheiden door een verticale streep |. </translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>Transactie-URLs van derde partijen</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Actieve commandoregelopties die bovenstaande opties overschrijven:</translation> </message> @@ -1349,8 +1357,8 @@ Adres: %4 <translation>Fout: Ongeldige combinatie van -regtest en -testnet</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> - <translation type="unfinished"/> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>Bitcoin Core is nog niet veilig uitgeschakeld...</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -2959,7 +2967,7 @@ bijvoorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo </message> <message> <source>Importing...</source> - <translation type="unfinished"/> + <translation>Importeren...</translation> </message> <message> <source>Incorrect or no genesis block found. Wrong datadir for network?</source> diff --git a/src/qt/locale/bitcoin_pam.ts b/src/qt/locale/bitcoin_pam.ts index 4a5e0363a8..22f1b7ccc3 100644 --- a/src/qt/locale/bitcoin_pam.ts +++ b/src/qt/locale/bitcoin_pam.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="pam" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="pam" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1046,6 +1046,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1347,7 +1355,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index 06845bfc3b..6bc177076b 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="pl" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="pl" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -739,7 +739,7 @@ Adres: %4 </message> <message> <source>none</source> - <translation type="unfinished"/> + <translation>żaden</translation> </message> <message> <source>Dust</source> @@ -1048,6 +1048,14 @@ Adres: %4 <translation>Adres IP serwera proxy (np. 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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1181,7 +1189,7 @@ Adres: %4 </message> <message> <source>none</source> - <translation type="unfinished"/> + <translation>żaden</translation> </message> <message> <source>Confirm options reset</source> @@ -1287,7 +1295,7 @@ Adres: %4 </message> <message> <source>Your active proxy doesn't support SOCKS5, which is required for payment requests via proxy.</source> - <translation type="unfinished"/> + <translation>Twoje aktywne proxy nie obsÅ‚uguje SOCKS5, co jest wymagane dla żądania pÅ‚atnoÅ›ci przez proxy.</translation> </message> <message> <source>Payment request fetch URL is invalid: %1</source> @@ -1349,8 +1357,8 @@ Adres: %4 <translation>BÅ‚Ä…d: Niepoprawna kombinacja -regtest i -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> - <translation type="unfinished"/> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>Bitcoin Core jeszcze siÄ™ nie wyÅ‚Ä…czyÅ‚ bezpiecznie…</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -1555,7 +1563,7 @@ Adres: %4 </message> <message> <source>Use this form to request payments. All fields are <b>optional</b>.</source> - <translation type="unfinished"/> + <translation>Użyj tego formularza do zażądania pÅ‚atnoÅ›ci. Wszystkie pola sÄ… <b>opcjonalne</b>.</translation> </message> <message> <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> @@ -2332,7 +2340,7 @@ Adres: %4 </message> <message> <source>Offline</source> - <translation type="unfinished"/> + <translation>Offline</translation> </message> <message> <source>Unconfirmed</source> @@ -2790,11 +2798,11 @@ na przykÅ‚ad: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo </message> <message> <source>(default: 1)</source> - <translation type="unfinished"/> + <translation>(domyÅ›lnie: 1)</translation> </message> <message> <source>(default: wallet.dat)</source> - <translation type="unfinished"/> + <translation>(domyÅ›lnie: wallet.dat)</translation> </message> <message> <source><category> can be:</source> @@ -2934,7 +2942,7 @@ na przykÅ‚ad: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo </message> <message> <source>Fees smaller than this are considered zero fee (for relaying) (default:</source> - <translation type="unfinished"/> + <translation>OpÅ‚aty mniejsze niż to sÄ… uznawane za nieistniejÄ…ce (przy przekazywaniu) (domyÅ›lnie:</translation> </message> <message> <source>Find peers using DNS lookup (default: 1 unless -connect)</source> @@ -2958,7 +2966,7 @@ na przykÅ‚ad: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo </message> <message> <source>Importing...</source> - <translation type="unfinished"/> + <translation>Importowanie…</translation> </message> <message> <source>Incorrect or no genesis block found. Wrong datadir for network?</source> @@ -3082,7 +3090,7 @@ na przykÅ‚ad: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo </message> <message> <source>Log transaction priority and fee per kB when mining blocks (default: 0)</source> - <translation type="unfinished"/> + <translation>Loguj priorytety transakcji i opÅ‚aty na kB podczas kopania bloków (domyÅ›lnie: 0)</translation> </message> <message> <source>Maintain a full transaction index (default: 0)</source> @@ -3106,7 +3114,7 @@ na przykÅ‚ad: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo </message> <message> <source>Print block on startup, if found in block index</source> - <translation type="unfinished"/> + <translation>WyÅ›wietlaj blok podczas uruchamiania, jeżeli znaleziono indeks bloków</translation> </message> <message> <source>Print block tree on startup (default: 0)</source> @@ -3122,7 +3130,7 @@ na przykÅ‚ad: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo </message> <message> <source>Randomly drop 1 of every <n> network messages</source> - <translation type="unfinished"/> + <translation>Losowo ignoruje 1 z każdych <n> wiadomoÅ›ci sieciowych.</translation> </message> <message> <source>Randomly fuzz 1 of every <n> network messages</source> @@ -3130,7 +3138,7 @@ na przykÅ‚ad: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo </message> <message> <source>Run a thread to flush wallet periodically (default: 1)</source> - <translation type="unfinished"/> + <translation>Uruchom wÄ…tek do okresowego zapisywania portfela (domyÅ›lnie: 1)</translation> </message> <message> <source>SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source> @@ -3138,7 +3146,7 @@ na przykÅ‚ad: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo </message> <message> <source>Send command to Bitcoin Core</source> - <translation type="unfinished"/> + <translation>WyÅ›lij komendÄ™ do Bitcoin Core</translation> </message> <message> <source>Send trace/debug info to console instead of debug.log file</source> @@ -3174,7 +3182,7 @@ na przykÅ‚ad: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo </message> <message> <source>Start Bitcoin Core Daemon</source> - <translation type="unfinished"/> + <translation>Uruchom serwer Bitcoin Core</translation> </message> <message> <source>System error: </source> @@ -3218,7 +3226,7 @@ na przykÅ‚ad: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo </message> <message> <source>on startup</source> - <translation type="unfinished"/> + <translation>podczas uruchamiania</translation> </message> <message> <source>version</source> diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index 94a87596ca..ee1c2a7381 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="pt_BR" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="pt_BR" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1047,6 +1047,14 @@ Endereço: %4</translation> <translation>Endereço de IP do proxy (e.g. 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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Ativa as opções de linha de comando que sobrescreve as opções acima:</translation> </message> @@ -1348,7 +1356,7 @@ Endereço: %4</translation> <translation>Erro: Combinação inválida de-regtest e testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index d6dbbbf42a..7a9595a6dd 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="pt_PT" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="pt_PT" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1047,6 +1047,14 @@ Endereço: %4</translation> <translation>Endereço IP do proxy (p.ex. 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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Opções de linha de comandos ativas que se sobrepõem ás opções anteriores:</translation> </message> @@ -1348,7 +1356,7 @@ Endereço: %4</translation> <translation>Erro: Combinação inválida de -regtest e -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts index 0a310db989..d09c40f62e 100644 --- a/src/qt/locale/bitcoin_ro_RO.ts +++ b/src/qt/locale/bitcoin_ro_RO.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ro_RO" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ro_RO" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -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> @@ -1048,6 +1048,14 @@ Adresa: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1349,7 +1357,7 @@ Adresa: %4 <translation>Eroare: combinaÈ›ie nevalidă de -regtest È™i -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> @@ -1579,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> @@ -3000,7 +3008,7 @@ spre exemplu: alertnotify=echo %%s | mail -s "Alerta Bitcoin" 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_ru.ts b/src/qt/locale/bitcoin_ru.ts index d9840a9c5e..570c3a61e7 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ru" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ru" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1048,6 +1048,14 @@ Address: %4 <translation>IP-Ð°Ð´Ñ€ÐµÑ Ð¿Ñ€Ð¾ÐºÑи (например 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>Сторонние URL (например, block explorer), которые отображаютÑÑ Ð½Ð° вкладке транзакций как пункты контекÑтного меню. %s в URL заменÑетÑÑ Ñ…Ñшем транзакции. URL отделÑÑŽÑ‚ÑÑ Ð´Ñ€ÑƒÐ³ от друга вертикальной чертой |.</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>Сторонние URL транзакций.</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Ðктивные опции командной Ñтроки, которые перекрывают вышеуказанные опции:</translation> </message> @@ -1349,8 +1357,8 @@ Address: %4 <translation>Ошибка: Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ¾Ð¼Ð±Ð¸Ð½Ð°Ñ†Ð¸Ñ -regtest и -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> - <translation>Bitcoin Core еще не готов к безопаÑному завершению...</translation> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>Bitcoin Core ещё не завершилÑÑ Ð±ÐµÐ·Ð¾Ð¿Ð°Ñно...</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> diff --git a/src/qt/locale/bitcoin_sah.ts b/src/qt/locale/bitcoin_sah.ts index 5cdf9a93d7..3bc3e65c62 100644 --- a/src/qt/locale/bitcoin_sah.ts +++ b/src/qt/locale/bitcoin_sah.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="sah" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="sah" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index b12462dbb2..bce535fad7 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="sk" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="sk" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -16,7 +16,12 @@ 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.</source> - <translation type="unfinished"/> + <translation> +Toto je experimentálny softvér. + +Distribuovaný pod MIT/X11 softvérovou licenciou, viÄ sprevádzajúci súbor COPYING alebo http://www.opensource.org/licenses/mit-license.php. + +Tento výrobok obsahuje sofvér, ktorý vyvynul OpenSSL Project pre použitie v OpenSSL Toolkit (http://www.openssl.org/) a kryptografický softvér napÃsaný Ericom Youngom (eay@cryptsoft.com) a UPnP softvér napÃsaný Thomasom Bernardom.</translation> </message> <message> <source>Copyright</source> @@ -28,7 +33,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>(%1-bit)</source> - <translation type="unfinished"/> + <translation>(%1-bit)</translation> </message> </context> <context> @@ -63,7 +68,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Delete the currently selected address from the list</source> - <translation type="unfinished"/> + <translation>Vymaž vybranú adresu zo zoznamu</translation> </message> <message> <source>Export the data in the current tab to a file</source> @@ -79,11 +84,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Choose the address to send coins to</source> - <translation type="unfinished"/> + <translation>Zvoľte adresu kam poslaÅ¥ coins</translation> </message> <message> <source>Choose the address to receive coins with</source> - <translation type="unfinished"/> + <translation>Zvoľte adresu na ktorú prijaÅ¥ coins</translation> </message> <message> <source>C&hoose</source> @@ -99,11 +104,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> - <translation type="unfinished"/> + <translation>Toto sú VaÅ¡e Bitcoin adresy pre posielanie platieb. Vždy skontrolujte množstvo a prijÃmaciu adresu pred poslanÃm coins.</translation> </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>Toto sú vaÅ¡e Bitcoin adresy pre prijÃmanie platieb. OdporúÄa sa použiÅ¥ novú prijÃmaciu adresu pre každú transakciu.</translation> </message> <message> <source>Copy &Label</source> @@ -127,7 +132,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>There was an error trying to save the address list to %1.</source> - <translation type="unfinished"/> + <translation>Nastala chyba pri pokuse uložiÅ¥ zoznam adries do %1.</translation> </message> </context> <context> @@ -209,7 +214,7 @@ This product includes software developed by the OpenSSL Project for use in the O </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 type="unfinished"/> + <translation>DÔLEŽITÉ: VÅ¡etky doterajÅ¡ie záložné kópie peňaženky ktoré ste zhotovili by mali byÅ¥ nahradené novým zaÅ¡ifrovaným súborom s peňaženkou. Z bezpeÄnostných dôvodov sa predchádzajúce kópie nezaÅ¡ifrovanej peňaženky stanú neužitoÄné keÄ zaÄnete použÃvaÅ¥ novú zaÅ¡ifrovanú peňaženku.</translation> </message> <message> <source>Warning: The Caps Lock key is on!</source> @@ -320,11 +325,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&Sending addresses...</source> - <translation type="unfinished"/> + <translation>Posielajúca adresa ...</translation> </message> <message> <source>&Receiving addresses...</source> - <translation type="unfinished"/> + <translation>PrijÃmajúca adresa...</translation> </message> <message> <source>Open &URI...</source> @@ -392,15 +397,15 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation type="unfinished"/> + <translation>ZaÅ¡ifruj súkromné kľúÄe ktoré patria do vaÅ¡ej peňaženky</translation> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation type="unfinished"/> + <translation>PodpÃsaÅ¥ správu s vaÅ¡ou adresou Bitcoin aby ste preukázali že ju vlastnÃte</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation type="unfinished"/> + <translation>OveriÅ¥ Äi správa bola podpÃsaná uvedenou Bitcoin adresou</translation> </message> <message> <source>&File</source> @@ -428,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished"/> + <translation>VyžiadaÅ¥ platbu (vygeneruje QR kód a bitcoin: URI)</translation> </message> <message> <source>&About Bitcoin Core</source> @@ -436,23 +441,23 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished"/> + <translation>ZobraziÅ¥ zoznam použitých adries odosielateľa a ich popisy</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished"/> + <translation>ZobraziÅ¥ zoznam použitých prijÃmacÃch adries a ich popisov</translation> </message> <message> <source>Open a bitcoin: URI or payment request</source> - <translation type="unfinished"/> + <translation>OtvoriÅ¥ bitcoin URI alebo výzvu k platbe</translation> </message> <message> <source>&Command-line options</source> - <translation>Voľby prÃkazového riadku</translation> + <translation>Možnosti prÃkazového riadku</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>ZobraziÅ¥ pomocnú správu od Bitcoin Jadra pre zÃskanie zoznamu dostupných možnostà prÃkazového riadku</translation> </message> <message> <source>Bitcoin client</source> @@ -488,15 +493,15 @@ 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 a %2</translation> </message> <message numerus="yes"> <source>%n year(s)</source> - <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation> + <translation><numerusform>%</numerusform><numerusform>%d)</numerusform><numerusform>%n rokov</numerusform></translation> </message> <message> <source>%1 behind</source> - <translation>%1 za</translation> + <translation>%1 pozadu</translation> </message> <message> <source>Last received block was generated %1 ago.</source> @@ -555,7 +560,7 @@ Adresa: %4</translation> </message> <message> <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation type="unfinished"/> + <translation>Vyskytla sa neblahá chyba. Bitcoin nemôže daľej bezpeÄne pokraÄovaÅ¥ a vypne sa.</translation> </message> </context> <context> @@ -569,7 +574,7 @@ Adresa: %4</translation> <name>CoinControlDialog</name> <message> <source>Coin Control Address Selection</source> - <translation type="unfinished"/> + <translation>Coin Control výber adresy</translation> </message> <message> <source>Quantity:</source> @@ -593,11 +598,11 @@ Adresa: %4</translation> </message> <message> <source>Low Output:</source> - <translation type="unfinished"/> + <translation>Malá hodnota na výstupe:</translation> </message> <message> <source>After Fee:</source> - <translation type="unfinished"/> + <translation>Po poplatku:</translation> </message> <message> <source>Change:</source> @@ -605,7 +610,7 @@ Adresa: %4</translation> </message> <message> <source>(un)select all</source> - <translation type="unfinished"/> + <translation>(ne)vybraÅ¥ vÅ¡etko</translation> </message> <message> <source>Tree mode</source> @@ -657,11 +662,11 @@ Adresa: %4</translation> </message> <message> <source>Lock unspent</source> - <translation type="unfinished"/> + <translation>Uzamknúť neminuté</translation> </message> <message> <source>Unlock unspent</source> - <translation type="unfinished"/> + <translation>Odomknúť neminuté</translation> </message> <message> <source>Copy quantity</source> @@ -673,7 +678,7 @@ Adresa: %4</translation> </message> <message> <source>Copy after fee</source> - <translation type="unfinished"/> + <translation>KopÃrovaÅ¥ za poplatok</translation> </message> <message> <source>Copy bytes</source> @@ -685,7 +690,7 @@ Adresa: %4</translation> </message> <message> <source>Copy low output</source> - <translation type="unfinished"/> + <translation>KopÃrovaÅ¥ malý výstup.</translation> </message> <message> <source>Copy change</source> @@ -729,7 +734,7 @@ Adresa: %4</translation> </message> <message> <source>(%1 locked)</source> - <translation type="unfinished"/> + <translation>(%1 zamknutých)</translation> </message> <message> <source>none</source> @@ -749,39 +754,39 @@ Adresa: %4</translation> </message> <message> <source>This label turns red, if the transaction size is greater than 1000 bytes.</source> - <translation type="unfinished"/> + <translation>Tento popis zÄervená ak veľkosÅ¥ transakcie presiahne 1000 bytov.</translation> </message> <message> <source>This means a fee of at least %1 per kB is required.</source> - <translation type="unfinished"/> + <translation>To znamená že požadovaný poplatok je aspoň %1 za kB.</translation> </message> <message> <source>Can vary +/- 1 byte per input.</source> - <translation type="unfinished"/> + <translation>Môže sa pohybovaÅ¥ +/- 1 bajt pre vstup.</translation> </message> <message> <source>Transactions with higher priority are more likely to get included into a block.</source> - <translation type="unfinished"/> + <translation>Transakcie s vysokou prioritou sa pravdepodobnejsie dostanú do bloku.</translation> </message> <message> <source>This label turns red, if the priority is smaller than "medium".</source> - <translation type="unfinished"/> + <translation>Tento popis zÄervenie ak je priorita nižÄia ako "medium".</translation> </message> <message> <source>This label turns red, if any recipient receives an amount smaller than %1.</source> - <translation type="unfinished"/> + <translation>Tento popis zÄervenie ak ktorýkoľvek prÃjemca dostane sumu menÅ¡iu ako %1.</translation> </message> <message> <source>This means a fee of at least %1 is required.</source> - <translation type="unfinished"/> + <translation>To znamená že je požadovaný poplatok aspoň %1.</translation> </message> <message> <source>Amounts below 0.546 times the minimum relay fee are shown as dust.</source> - <translation type="unfinished"/> + <translation>Sumy pod 0.546 násobkom minimálneho poplatku pre prenos sú považované za prach.</translation> </message> <message> <source>This label turns red, if the change is smaller than %1.</source> - <translation type="unfinished"/> + <translation>Tento popis zžervenie ak výdavok je menÅ¡Ã než %1.</translation> </message> <message> <source>(no label)</source> @@ -808,11 +813,11 @@ Adresa: %4</translation> </message> <message> <source>The label associated with this address list entry</source> - <translation type="unfinished"/> + <translation>Popis tejto položký v zozname adries je prázdny</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>Adresa spojená s týmto záznamom v adresári. Možno upravovaÅ¥ len pre odosielajúce adresy.</translation> </message> <message> <source>&Address</source> @@ -863,7 +868,7 @@ Adresa: %4</translation> </message> <message> <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> - <translation type="unfinished"/> + <translation>PrieÄinok už existuje. Pridajte "%1" ak chcete vytvoriÅ¥ nový prieÄinok tu.</translation> </message> <message> <source>Path already exists, and is not a directory.</source> @@ -878,7 +883,7 @@ Adresa: %4</translation> <name>HelpMessageDialog</name> <message> <source>Bitcoin Core - Command-line options</source> - <translation type="unfinished"/> + <translation>Jadro Bitcoin - možnosti prÃkazového riadku</translation> </message> <message> <source>Bitcoin Core</source> @@ -910,7 +915,7 @@ Adresa: %4</translation> </message> <message> <source>Set SSL root certificates for payment request (default: -system-)</source> - <translation type="unfinished"/> + <translation>NastaviÅ¥ koreňový certifikát pre výzvy na platbu (prednastavené: -system-)</translation> </message> <message> <source>Show splash screen on startup (default: 1)</source> @@ -918,7 +923,7 @@ Adresa: %4</translation> </message> <message> <source>Choose data directory on startup (default: 0)</source> - <translation type="unfinished"/> + <translation>Zvoľte dátový prieÄinok pri Å¡tarte (prednastavené: 0)</translation> </message> </context> <context> @@ -933,11 +938,11 @@ Adresa: %4</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>KeÄže spúštate program prvý krát, môžte si vybraÅ¥ kde bude Bitcoin Jadro ukladaÅ¥ svoje dáta.</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>Jadro Bitcoin stiahne zo siete a uložà kópiu Bitcoin blockchain. Aspoň %1GB dát bude uložených v tomto prieÄinku a Äasom porastie. Peňaženka bude tiež uložená v tomto prieÄinku.</translation> </message> <message> <source>Use the default data directory</source> @@ -953,7 +958,7 @@ Adresa: %4</translation> </message> <message> <source>Error: Specified data directory "%1" can not be created.</source> - <translation type="unfinished"/> + <translation>Chyba: PredpÃsaný prieÄinok pre dáta "%1" nemôže byt vytvorený.</translation> </message> <message> <source>Error</source> @@ -976,7 +981,7 @@ Adresa: %4</translation> </message> <message> <source>Open payment request from URI or file</source> - <translation type="unfinished"/> + <translation>OtvoriÅ¥ požiadavku na zaplatenie z URI alebo súboru</translation> </message> <message> <source>URI:</source> @@ -984,11 +989,11 @@ Adresa: %4</translation> </message> <message> <source>Select payment request file</source> - <translation type="unfinished"/> + <translation>Vyberte súbor s výzvou k platbe</translation> </message> <message> <source>Select payment request file to open</source> - <translation type="unfinished"/> + <translation>Vyberte ktorý súbor s výzvou k platbe otvoriÅ¥</translation> </message> </context> <context> @@ -1003,7 +1008,7 @@ Adresa: %4</translation> </message> <message> <source>Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB.</source> - <translation type="unfinished"/> + <translation>Voliteľný transakÄný poplatok za kB ktorý pomôže rýchlemu spracovaniu transakcie. VäÄÅ¡ina transakcià má 1 kB. Poplatok 0.01 je odporúÄaný.</translation> </message> <message> <source>Pay transaction &fee</source> @@ -1019,7 +1024,7 @@ Adresa: %4</translation> </message> <message> <source>Size of &database cache</source> - <translation type="unfinished"/> + <translation>VeľkosÅ¥ vyrovnávacej pamäti databázy</translation> </message> <message> <source>MB</source> @@ -1027,23 +1032,31 @@ Adresa: %4</translation> </message> <message> <source>Number of script &verification threads</source> - <translation type="unfinished"/> + <translation>PoÄet skript overujucich vlákien</translation> </message> <message> <source>Connect to the Bitcoin network through a SOCKS proxy.</source> - <translation type="unfinished"/> + <translation>PripojiÅ¥ k Bitcoin sieti cez SOCKS proxy.</translation> </message> <message> <source>&Connect through SOCKS proxy (default proxy):</source> - <translation type="unfinished"/> + <translation>PripojiÅ¥ sa cez SOCKS proxy (predvolené 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 adresy proxy (napr. 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>URL tretÃch strán (napr. prehliadaÄ blockchain) ktoré sa zobrazujú v záložke transakcià ako položky kontextového menu. %s v URL je nahradené hash-om transakcie. Viaceré URL sú oddelené zvislou Äiarou |.</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>URL transakcià s tretÃmi stranami</translation> </message> <message> <source>Active command-line options that override above options:</source> - <translation type="unfinished"/> + <translation>Aktévne možnosti prÃkazového riadku ktoré prepÃÅ¡u možnosti vyÅ¡Å¡ie:</translation> </message> <message> <source>Reset all client options to default.</source> @@ -1059,27 +1072,27 @@ Adresa: %4</translation> </message> <message> <source>(0 = auto, <0 = leave that many cores free)</source> - <translation type="unfinished"/> + <translation>(0 = auto, <0 = nechaÅ¥ toľko jadier voľných)</translation> </message> <message> <source>W&allet</source> - <translation type="unfinished"/> + <translation>Peňaženka</translation> </message> <message> <source>Expert</source> - <translation type="unfinished"/> + <translation>Expert</translation> </message> <message> <source>Enable coin &control features</source> - <translation type="unfinished"/> + <translation>PovoliÅ¥ možnosti coin control</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>Ak vypnete mÃňanie nepotvrdeného výdavku tak výdavok z transakcie bude možné použiÅ¥ až keÄ daná transakcia bude maÅ¥ aspoň jedno potvrdenie. Toto má vplyv aj na výpoÄet vášho zostatku.</translation> </message> <message> <source>&Spend unconfirmed change</source> - <translation type="unfinished"/> + <translation>Minúť nepotvrdený výdavok</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> @@ -1139,7 +1152,7 @@ Adresa: %4</translation> </message> <message> <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin.</source> - <translation type="unfinished"/> + <translation>Tu sa dá nastaviÅ¥ jazyk užÃvateľského rozhrania. Toto nastavenie bude úÄinné po reÅ¡tartovanà Bitcoin.</translation> </message> <message> <source>&Unit to show amounts in:</source> @@ -1147,11 +1160,11 @@ Adresa: %4</translation> </message> <message> <source>Choose the default subdivision unit to show in the interface and when sending coins.</source> - <translation type="unfinished"/> + <translation>Zvoľte ako deliÅ¥ bitcoin pri zobrazovanà pri platbách a užÃvateľskom rozhranÃ.</translation> </message> <message> <source>Whether to show Bitcoin addresses in the transaction list or not.</source> - <translation type="unfinished"/> + <translation>ÄŒi ukazovaÅ¥ Bitcoin adresy v zozname transakcià alebo nie.</translation> </message> <message> <source>&Display addresses in transaction list</source> @@ -1159,7 +1172,7 @@ Adresa: %4</translation> </message> <message> <source>Whether to show coin control features or not.</source> - <translation type="unfinished"/> + <translation>ÄŒi zobrazovaÅ¥ možnosti "Coin control" alebo nie.</translation> </message> <message> <source>&OK</source> @@ -1179,19 +1192,19 @@ Adresa: %4</translation> </message> <message> <source>Confirm options reset</source> - <translation type="unfinished"/> + <translation>PotvrdiÅ¥ obnovenie možnostÃ</translation> </message> <message> <source>Client restart required to activate changes.</source> - <translation type="unfinished"/> + <translation>ReÅ¡tart klienta potrebný pre aktivovanie zmien.</translation> </message> <message> <source>Client will be shutdown, do you want to proceed?</source> - <translation type="unfinished"/> + <translation>Klient bude vypnutý, chcete pokraÄovaÅ¥?</translation> </message> <message> <source>This change would require a client restart.</source> - <translation type="unfinished"/> + <translation>Táto zmena by vyžadovala reÅ¡tart klienta.</translation> </message> <message> <source>The supplied proxy address is invalid.</source> @@ -1206,7 +1219,7 @@ Adresa: %4</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> - <translation type="unfinished"/> + <translation>Zobrazené informácie môžu byÅ¥ neaktuápne. VaÅ¡a peňaženka sa automaticky synchronizuje so sieÅ¥ou Bitcoin po nadviazanà spojenia ale tento proces eÅ¡te nieje ukonÄený.</translation> </message> <message> <source>Wallet</source> @@ -1214,19 +1227,19 @@ Adresa: %4</translation> </message> <message> <source>Available:</source> - <translation type="unfinished"/> + <translation>Disponibilné:</translation> </message> <message> <source>Your current spendable balance</source> - <translation type="unfinished"/> + <translation>Váš aktuálny disponibilný zostatok</translation> </message> <message> <source>Pending:</source> - <translation type="unfinished"/> + <translation>ÄŒakajúce potvrdenie</translation> </message> <message> <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> - <translation type="unfinished"/> + <translation>Suma transakcià ktoré eÅ¡te neboli potvrdené a eÅ¡te sa nepoÄÃtajú do disponibilného zostatku</translation> </message> <message> <source>Immature:</source> @@ -1234,7 +1247,7 @@ Adresa: %4</translation> </message> <message> <source>Mined balance that has not yet matured</source> - <translation type="unfinished"/> + <translation>Vytvorený zostatok ktorý eÅ¡te nedosiahol zrelosÅ¥</translation> </message> <message> <source>Total:</source> @@ -1261,55 +1274,55 @@ Adresa: %4</translation> </message> <message> <source>URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> - <translation type="unfinished"/> + <translation>URI sa nedá rozložiÅ¥! To môže byÅ¥ spôsobené neplatou Bitcoin adresou alebo zle upravenými vlastnosÅ¥ami URI.</translation> </message> <message> <source>Requested payment amount of %1 is too small (considered dust).</source> - <translation type="unfinished"/> + <translation>Požadovaná platba sumy %1 je prÃliÅ¡ malá (považovaná za prach).</translation> </message> <message> <source>Payment request error</source> - <translation type="unfinished"/> + <translation>Chyba pri vyžiadanà platby</translation> </message> <message> <source>Cannot start bitcoin: click-to-pay handler</source> - <translation type="unfinished"/> + <translation>Nedá sa spustiÅ¥ obslužný program bitcoin: click-to-pay zaplatiÅ¥ kliknutÃm</translation> </message> <message> <source>Net manager warning</source> - <translation type="unfinished"/> + <translation>Varovanie správcu siete</translation> </message> <message> <source>Your active proxy doesn't support SOCKS5, which is required for payment requests via proxy.</source> - <translation type="unfinished"/> + <translation>VaÅ¡e aktÃvne proxy nepodporuje SOCKS5, ktoré je potrebné pre vyzvu na zaplatenie cez proxy.</translation> </message> <message> <source>Payment request fetch URL is invalid: %1</source> - <translation type="unfinished"/> + <translation>URL pre stiahnutie výzvy na zaplatenie je neplatné: %1</translation> </message> <message> <source>Payment request file handling</source> - <translation type="unfinished"/> + <translation>Obsluha súboru s požiadavkou na platbu</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>Súbor s výzvou na zaplatenie sa nedá ÄÃtaÅ¥ alebo spracovaÅ¥! To môže byÅ¥ spôsobené aj neplatným súborom s výzvou.</translation> </message> <message> <source>Unverified payment requests to custom payment scripts are unsupported.</source> - <translation type="unfinished"/> + <translation>Program nepodporuje neoverené platobné výzvy na vlastná skripty.</translation> </message> <message> <source>Refund from %1</source> - <translation type="unfinished"/> + <translation>Vrátenie z %1</translation> </message> <message> <source>Error communicating with %1: %2</source> - <translation type="unfinished"/> + <translation>Chyba komunikácie s %1: %2 </translation> </message> <message> <source>Payment request can not be parsed or processed!</source> - <translation type="unfinished"/> + <translation>Požiadavka na platbu nemôže byÅ¥ analyzovaná alebo spracovaná!</translation> </message> <message> <source>Bad response from server %1</source> @@ -1317,11 +1330,11 @@ Adresa: %4</translation> </message> <message> <source>Payment acknowledged</source> - <translation type="unfinished"/> + <translation>Platba potvrdená</translation> </message> <message> <source>Network request error</source> - <translation type="unfinished"/> + <translation>Chyba požiadavky siete</translation> </message> </context> <context> @@ -1332,19 +1345,19 @@ Adresa: %4</translation> </message> <message> <source>Error: Specified data directory "%1" does not exist.</source> - <translation type="unfinished"/> + <translation>Chyba: Uvedený prieÄinok s dátami "%1" neexistuje.</translation> </message> <message> <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source> - <translation type="unfinished"/> + <translation>Chyba: Nedá sa rozlúštit súbor s nastaveniami: %1. PoužÃvajte výluÄne kľúÄ=hodnota syntax.</translation> </message> <message> <source>Error: Invalid combination of -regtest and -testnet.</source> - <translation type="unfinished"/> + <translation>Chyba: Nesprávna kombinácia -regtest a -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> - <translation type="unfinished"/> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>Jadro Bitcoin sa eÅ¡te úspeÅ¡ne nevyplo ...</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -1470,7 +1483,7 @@ Adresa: %4</translation> </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 type="unfinished"/> + <translation>OtvoriÅ¥ Bitcoin log súbor pre ladenie z aktuálneho dátového adresára. Toto môže trvaÅ¥ niekoľko sekúnd pre veľké súbory.</translation> </message> <message> <source>Clear console</source> @@ -1478,15 +1491,15 @@ Adresa: %4</translation> </message> <message> <source>Welcome to the Bitcoin RPC console.</source> - <translation type="unfinished"/> + <translation>Vitajte v Bitcoin RPC konzole. BanÃk, pyÄo!</translation> </message> <message> <source>Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.</source> - <translation type="unfinished"/> + <translation>Použi Å¡ipky hore a dolu pre navigáciu históriou a <b>Ctrl-L</b> pre vyÄistenie obrazovky.</translation> </message> <message> <source>Type <b>help</b> for an overview of available commands.</source> - <translation type="unfinished"/> + <translation>NapÃÅ¡ <b>help</b> pre prehľad dostupných prÃkazov.</translation> </message> <message> <source>%1 B</source> @@ -1533,27 +1546,27 @@ Adresa: %4</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>Znovu použiÅ¥ jednu z už použitých adries pre prijÃmanie. Znovu použÃvanie adries je sporná otázka bezpeÄnosti aj súkromia. PoužÃvajte to len v prÃpade ak znovu generujete výzvu na zaplatenie ktorú ste už vyrobili v minulosti.</translation> </message> <message> <source>R&euse an existing receiving address (not recommended)</source> - <translation type="unfinished"/> + <translation>Znovu použiÅ¥ jestvujúcu prijÃmaciu adresu (neodporúÄa sa)</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>PridaÅ¥ voliteľnú správu k výzve na zaplatenie, ktorá sa zobrazà keÄ bude výzva otvorená. Poznámka: Správa nebude poslaná s platbou cez sieÅ¥ Bitcoin.</translation> </message> <message> <source>An optional label to associate with the new receiving address.</source> - <translation type="unfinished"/> + <translation>Voliteľný popis ktorý sa pridá k tejto novej prijÃmajúcej adrese.</translation> </message> <message> <source>Use this form to request payments. All fields are <b>optional</b>.</source> - <translation type="unfinished"/> + <translation>Použite tento formulár pre vyžiadanie platby. VÅ¡etky polia sú <b>voliteľné</b>.</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>Voliteľná požadovaná suma. Nechajte prázdne alebo nulu ak nepožadujete urÄitú sumu.</translation> </message> <message> <source>Clear all fields of the form.</source> @@ -1573,7 +1586,7 @@ Adresa: %4</translation> </message> <message> <source>Show the selected request (does the same as double clicking an entry)</source> - <translation type="unfinished"/> + <translation>Zobraz zvolenú požiadavku (urobà to isté ako dvoj-klik na záznam)</translation> </message> <message> <source>Show</source> @@ -1581,7 +1594,7 @@ Adresa: %4</translation> </message> <message> <source>Remove the selected entries from the list</source> - <translation type="unfinished"/> + <translation>OdstrániÅ¥ zvolené záznamy zo zoznamu</translation> </message> <message> <source>Remove</source> @@ -1694,7 +1707,7 @@ Adresa: %4</translation> </message> <message> <source>Coin Control Features</source> - <translation type="unfinished"/> + <translation>Možnosti "Coin Control"</translation> </message> <message> <source>Inputs...</source> @@ -1730,11 +1743,11 @@ Adresa: %4</translation> </message> <message> <source>Low Output:</source> - <translation type="unfinished"/> + <translation>Malá hodnota na výstupe:</translation> </message> <message> <source>After Fee:</source> - <translation type="unfinished"/> + <translation>Po poplatku:</translation> </message> <message> <source>Change:</source> @@ -1742,7 +1755,7 @@ Adresa: %4</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>Ak aktivované ale adresa pre výdavok je prázdna alebo neplatná, výdavok bude poslaný na novovytvorenú adresu.</translation> </message> <message> <source>Custom change address</source> @@ -1798,7 +1811,7 @@ Adresa: %4</translation> </message> <message> <source>Copy after fee</source> - <translation type="unfinished"/> + <translation>KopÃrovaÅ¥ za poplatok</translation> </message> <message> <source>Copy bytes</source> @@ -1810,7 +1823,7 @@ Adresa: %4</translation> </message> <message> <source>Copy low output</source> - <translation type="unfinished"/> + <translation>KopÃrovaÅ¥ nÃzky výstup</translation> </message> <message> <source>Copy change</source> @@ -1850,11 +1863,11 @@ Adresa: %4</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>Transakcia bola zamietnutá! Toto sa môže staÅ¥ ak niektoré coins vo vaÅ¡ej peňaženke už boli minuté, ako keÄ použijete kópiu wallet.dat a coins boli minuté z kópie ale neoznaÄené ako minuté tu.</translation> </message> <message> <source>Warning: Invalid Bitcoin address</source> - <translation type="unfinished"/> + <translation>Varovanie: Nesprávna Bitcoin adresa</translation> </message> <message> <source>(no label)</source> @@ -1862,7 +1875,7 @@ Adresa: %4</translation> </message> <message> <source>Warning: Unknown change address</source> - <translation type="unfinished"/> + <translation>Varovanie: Neznáma adresa pre výdavok</translation> </message> <message> <source>Are you sure you want to send?</source> @@ -1874,7 +1887,7 @@ Adresa: %4</translation> </message> <message> <source>Payment request expired</source> - <translation type="unfinished"/> + <translation>VyprÅ¡ala platnosÅ¥ požiadavky na platbu</translation> </message> <message> <source>Invalid payment address %1</source> @@ -1933,19 +1946,19 @@ Adresa: %4</translation> </message> <message> <source>This is a verified payment request.</source> - <translation type="unfinished"/> + <translation>Toto je overená výzva k platbe.</translation> </message> <message> <source>Enter a label for this address to add it to the list of used addresses</source> - <translation type="unfinished"/> + <translation>Vložte popis pre túto adresu aby sa uložila do zoznamu použitých adries</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>Správa ktorá bola pripojená k bitcoin: URI a ktorá bude uložená s transakcou pre VaÅ¡e potreby. Poznámka: Táto správa nebude poslaná cez sieÅ¥ Bitcoin.</translation> </message> <message> <source>This is an unverified payment request.</source> - <translation type="unfinished"/> + <translation>Toto je neoverená výzva k platbe.</translation> </message> <message> <source>Pay To:</source> @@ -1953,7 +1966,7 @@ Adresa: %4</translation> </message> <message> <source>Memo:</source> - <translation type="unfinished"/> + <translation>Poznámka:</translation> </message> </context> <context> @@ -1964,14 +1977,14 @@ Adresa: %4</translation> </message> <message> <source>Do not shut down the computer until this window disappears.</source> - <translation type="unfinished"/> + <translation>NevypÃnajte poÄÃtaÄ kým toto okno nezmizne.</translation> </message> </context> <context> <name>SignVerifyMessageDialog</name> <message> <source>Signatures - Sign / Verify a Message</source> - <translation type="unfinished"/> + <translation>Podpisy - PodpÃsaÅ¥ / OveriÅ¥ správu</translation> </message> <message> <source>&Sign Message</source> @@ -2011,7 +2024,7 @@ Adresa: %4</translation> </message> <message> <source>Copy the current signature to the system clipboard</source> - <translation type="unfinished"/> + <translation>KopÃrovaÅ¥ práve zvolenú adresu do systémového klipbordu</translation> </message> <message> <source>Sign the message to prove you own this Bitcoin address</source> @@ -2023,7 +2036,7 @@ Adresa: %4</translation> </message> <message> <source>Reset all sign message fields</source> - <translation type="unfinished"/> + <translation>VynulovaÅ¥ vÅ¡etky polia podpisu správy</translation> </message> <message> <source>Clear &All</source> @@ -2035,7 +2048,7 @@ Adresa: %4</translation> </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 type="unfinished"/> + <translation>Vložte podpisovaciu adresu, správu (uistite sa, že kopÃrujete ukonÄenia riadkov, medzery, odrážky, atÄ. presne) a podpis pod to na overenie adresy. BuÄte opatrnà a neÄÃtajte ako podpÃsané viac než je v samotnej podpÃsanej správe a môžete sa tak vyhnúť podvodu mitm útokom.</translation> </message> <message> <source>The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -2043,7 +2056,7 @@ Adresa: %4</translation> </message> <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> - <translation type="unfinished"/> + <translation>OverÃm správy sa uistiÅ¥ že bola podpÃsaná oznaÄenou Bitcoin adresou</translation> </message> <message> <source>Verify &Message</source> @@ -2051,7 +2064,7 @@ Adresa: %4</translation> </message> <message> <source>Reset all verify message fields</source> - <translation type="unfinished"/> + <translation>ObnoviÅ¥ vÅ¡etky polia v overiÅ¥ správu</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -2071,7 +2084,7 @@ Adresa: %4</translation> </message> <message> <source>The entered address does not refer to a key.</source> - <translation type="unfinished"/> + <translation>Vložená adresa nezodpovedá žiadnemu kľúcu.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -2079,7 +2092,7 @@ Adresa: %4</translation> </message> <message> <source>Private key for the entered address is not available.</source> - <translation type="unfinished"/> + <translation>Súkromný kÄ¾ÃºÄ pre vložená adresu nieje k dispozÃcii.</translation> </message> <message> <source>Message signing failed.</source> @@ -2099,7 +2112,7 @@ Adresa: %4</translation> </message> <message> <source>The signature did not match the message digest.</source> - <translation type="unfinished"/> + <translation>Podpis sa nezhoduje so zhrnutÃm správy</translation> </message> <message> <source>Message verification failed.</source> @@ -2140,7 +2153,7 @@ Adresa: %4</translation> </message> <message> <source>conflicted</source> - <translation type="unfinished"/> + <translation>sporné</translation> </message> <message> <source>%1/offline</source> @@ -2160,7 +2173,7 @@ Adresa: %4</translation> </message> <message numerus="yes"> <source>, broadcast through %n node(s)</source> - <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation> + <translation><numerusform>,</numerusform><numerusform>,</numerusform><numerusform>, vysielaÅ¥ cez %n nód</numerusform></translation> </message> <message> <source>Date</source> @@ -2196,7 +2209,7 @@ Adresa: %4</translation> </message> <message numerus="yes"> <source>matures in %n more block(s)</source> - <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation> + <translation><numerusform>Dospeje o %n blokov</numerusform><numerusform>Dospeje o %n blokov</numerusform><numerusform>dospeje o %n blokov</numerusform></translation> </message> <message> <source>not accepted</source> @@ -2232,7 +2245,7 @@ Adresa: %4</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 "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> - <translation type="unfinished"/> + <translation>Vytvorené coins musia dospieÅ¥ %1 blokov kým môžu byÅ¥ minuté. KeÄ vytvorÃte tento blok, bude rozoslaný do siete aby bol akceptovaný do reÅ¥aze blokov. Ak sa nedostane reÅ¥aze, jeho stav sa zmenà na "zamietnutý" a nebude sa daÅ¥ minúť. Toto sa môže obÄas staÅ¥ ak iná nóda vytvorà blok približne v tom istom Äase.</translation> </message> <message> <source>Debug information</source> @@ -2264,7 +2277,7 @@ Adresa: %4</translation> </message> <message numerus="yes"> <source>Open for %n more block(s)</source> - <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation> + <translation><numerusform>OtvoriÅ¥ pre %n viac blok</numerusform><numerusform>OtvoriÅ¥ pre %n viac blokov </numerusform><numerusform>OtvoriÅ¥ pre %n viac blokov </numerusform></translation> </message> <message> <source>unknown</source> @@ -2302,11 +2315,11 @@ Adresa: %4</translation> </message> <message> <source>Immature (%1 confirmations, will be available after %2)</source> - <translation type="unfinished"/> + <translation>Nezrelé (%1 potvrdenÃ, bude k dispozÃcii po %2)</translation> </message> <message numerus="yes"> <source>Open for %n more block(s)</source> - <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation> + <translation><numerusform>Otvorené pre eÅ¡te %1 blok</numerusform><numerusform>Otvorené pre %n viac blokov </numerusform><numerusform>Otvorené pre %n blokov</numerusform></translation> </message> <message> <source>Open until %1</source> @@ -2326,19 +2339,19 @@ Adresa: %4</translation> </message> <message> <source>Offline</source> - <translation type="unfinished"/> + <translation>Offline</translation> </message> <message> <source>Unconfirmed</source> - <translation type="unfinished"/> + <translation>Nepotvrdené</translation> </message> <message> <source>Confirming (%1 of %2 recommended confirmations)</source> - <translation type="unfinished"/> + <translation> Potvrdzuje sa ( %1 z %2 odporúÄaných potvrdenÃ)</translation> </message> <message> <source>Conflicted</source> - <translation type="unfinished"/> + <translation>V rozpore</translation> </message> <message> <source>Received with</source> @@ -2477,7 +2490,7 @@ Adresa: %4</translation> </message> <message> <source>There was an error trying to save the transaction history to %1.</source> - <translation type="unfinished"/> + <translation>Vyskytla sa chyba pri pokuse o uloženie histórie transakcià do %1.</translation> </message> <message> <source>Exporting Successful</source> @@ -2485,7 +2498,7 @@ Adresa: %4</translation> </message> <message> <source>The transaction history was successfully saved to %1.</source> - <translation type="unfinished"/> + <translation>História transakciá bola úspeÅ¡ne uložená do %1.</translation> </message> <message> <source>Comma separated file (*.csv)</source> @@ -2566,11 +2579,11 @@ Adresa: %4</translation> </message> <message> <source>There was an error trying to save the wallet data to %1.</source> - <translation type="unfinished"/> + <translation>Vyskytla sa chyba pri pokuse o uloženie dát peňaženky do %1.</translation> </message> <message> <source>The wallet data was successfully saved to %1.</source> - <translation type="unfinished"/> + <translation>Dáta peňaženky boli úspeÅ¡ne uložené do %1.</translation> </message> <message> <source>Backup Successful</source> @@ -2617,7 +2630,7 @@ Adresa: %4</translation> </message> <message> <source>Connect to a node to retrieve peer addresses, and disconnect</source> - <translation type="unfinished"/> + <translation>PripojiÅ¥ sa k nóde, zÃskaÅ¥ adresy ÄaľšÃch poÄÃtaÄov v sieti a odpojit sa.</translation> </message> <message> <source>Specify your own public address</source> @@ -2633,7 +2646,7 @@ Adresa: %4</translation> </message> <message> <source>An error occurred while setting up the RPC port %u for listening on IPv4: %s</source> - <translation type="unfinished"/> + <translation>Vyskytla sa chyba pri nastavovanà RPC portu %u pre poÄúvanie na IPv4: %s</translation> </message> <message> <source>Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)</source> @@ -2645,7 +2658,7 @@ Adresa: %4</translation> </message> <message> <source>Bitcoin Core RPC client version</source> - <translation type="unfinished"/> + <translation>Verzia RPC klienta Jadra Bitcoin</translation> </message> <message> <source>Run in the background as a daemon and accept commands</source> @@ -2657,7 +2670,7 @@ Adresa: %4</translation> </message> <message> <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source> - <translation type="unfinished"/> + <translation>PrijaÅ¥ spojenia zvonku (predvolené: 1 ak žiadne -proxy alebo -connect)</translation> </message> <message> <source>%s, you must set a rpcpassword in the configuration file: @@ -2671,83 +2684,93 @@ If the file does not exist, create it with owner-readable-only file permissions. It is also recommended to set alertnotify so you are notified of problems; for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com </source> - <translation type="unfinished"/> + <translation>%s, musÃte nastaviÅ¥ rpcpassword heslo v súbore nastavenÃ: +%s +OdporúÄa sa použÃvaÅ¥ nasledujúce náhodné heslo: +rpcuser=bitcoinrpc +rpcpassword=%s +(nemusÃte si pamätaÅ¥ toto heslo) +UžÃvateľské meno a heslo NESMÚ byÅ¥ rovnaké. +Ak súbor neexistuje, vytvorte ho s prÃstupovým právom owner-readable-only Äitateľné len pre majiteľa. +Tiež sa odporúÄa nastaviÅ¥ alertnotify aby ste boli upozorňovanà na problémy; +naprÃklad: alertnotify=echo %%s | mail -s "Bitcoin Výstraha" 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>Prijateľlné Å¡ifry (prednastavené: 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> - <translation type="unfinished"/> + <translation>Vyskytla sa chyba pri nastavovanà RPC portu %u pre poÄúvanie na IPv6, vraciam sa späť ku IPv4: %s</translation> </message> <message> <source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source> - <translation type="unfinished"/> + <translation>SpojiÅ¥ s danou adresou a vždy na nej poÄúvaÅ¥. Použite zápis [host]:port pre IPv6</translation> </message> <message> <source>Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:15)</source> - <translation type="unfinished"/> + <translation>Priebežne obmedzuj transakcie bez poplatku na <n>*1000 bajtov za minútu (prednastavené: 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>VstúpiÅ¥ do regresného testovacieho módu, ktorý použÃva Å¡peciálnu reÅ¥az v ktorej môžu byÅ¥ bloky v okamihu vyrieÅ¡ené. Pre úÄely regresného testovania a vývoja aplikácie.</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>VojsÅ¥ do režimu regresného testovania, ktorý použÃva Å¡peciálnu reÅ¥az v ktorej môžu byÅ¥ bloky v okamihu vyrieÅ¡ené.</translation> </message> <message> <source>Error: Listening for incoming connections failed (listen returned error %d)</source> - <translation type="unfinished"/> + <translation>Chyba: Zlyhalo poÄúvanie prichádzajúcich spojenà (listen vrátil chybu %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> - <translation type="unfinished"/> + <translation>Transakcia bola zamietnutá! Toto sa môže staÅ¥ ak niektoré coins vo vaÅ¡ej peňaženke už boli minuté, ako keÄ použijete kópiu wallet.dat a coins boli minuté z kópie ale neoznaÄené ako minuté tu.</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> - <translation type="unfinished"/> + <translation>Chyba: Táto transakcia vyžaduje transakÄný poplatok aspoň %s kvôli svojej sume, komplexite alebo použitiu nedávno prijatých prostriedkov.</translation> </message> <message> <source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source> - <translation type="unfinished"/> + <translation>Vykonaj prÃkaz keÄ sa zmenà transakcia peňaženky (%s v prÃkaze je nahradená TxID)</translation> </message> <message> <source>Fees smaller than this are considered zero fee (for transaction creation) (default:</source> - <translation type="unfinished"/> + <translation>Poplatky menÅ¡ie než toto sa považujú za nulové (pre vytvorenie transakcie) (prednastavené:</translation> </message> <message> <source>Flush database activity from memory pool to disk log every <n> megabytes (default: 100)</source> - <translation type="unfinished"/> + <translation>OdložiÅ¥ aktivitu databázy spoloÄnej pamäti do logu na disku každých <n> megabajtov (prednastavené: 100)</translation> </message> <message> <source>How thorough the block verification of -checkblocks is (0-4, default: 3)</source> - <translation type="unfinished"/> + <translation>Ako dôkladne sú overované bloky -checkblocks (0-4, prednastavené: 3)</translation> </message> <message> <source>In this mode -genproclimit controls how many blocks are generated immediately.</source> - <translation type="unfinished"/> + <translation>V tomto režime -getproclimit kontroluje koľko blokov sa vytvorà okamžite.</translation> </message> <message> <source>Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)</source> - <translation type="unfinished"/> + <translation>NastaviÅ¥ poÄeÅ¥ vlákien overujúcich skripty (%u až %d, 0 = auto, <0 = nechaÅ¥ toľkoto jadier voľných, prednastavené: %d)</translation> </message> <message> <source>Set the processor limit for when generation is on (-1 = unlimited, default: -1)</source> - <translation type="unfinished"/> + <translation>NastaviÅ¥ obmedzenie pre procesor keÄ je zapnuté generovanie (-1 = bez obmedzenia, prednastavené: -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> - <translation type="unfinished"/> + <translation>Toto je pred-testovacia verzia - použitie je na vlastné riziko - nepoužÃvajte na tvorbu bitcoin ani obchodovanie.</translation> </message> <message> <source>Unable to bind to %s on this computer. Bitcoin Core is probably already running.</source> - <translation type="unfinished"/> + <translation>Nepodarilo sa pripojiÅ¥ na %s na tomto poÄÃtaÄi. Bitcoin Jadro je už pravdepodobne spustené.</translation> </message> <message> <source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)</source> - <translation type="unfinished"/> + <translation>Použite rozdielne SOCKS5 proxy pre dosiahnutie peer-ov cez Tor skryté služby (prednastavené: -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> @@ -2755,31 +2778,33 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin will not work properly.</source> - <translation type="unfinished"/> + <translation>Varovanie: Skontroluj Äi je na poÄÃtaÄi nastavený správny Äas a dátum. Ak sú hodiny nastavené nesprávne, Bitcoin nebude správne pracovaÅ¥.</translation> </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> - <translation type="unfinished"/> + <translation>Varovanie: Javà sa že sieÅ¥ sieÅ¥ úplne nesúhlasÃ! Niektorà mineri zjavne majú Å¥ažkosti. + +The network does not appear to fully agree! Some miners appear to be experiencing issues.</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>Varovanie: Zjavne sa úplne nezhodujeme s naÅ¡imi peer-mi! Možno potrebujete prejsÅ¥ na novÅ¡iu verziu alebo ostatné nódy potrebujú vyÅ¡Å¡iu verziu.</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> - <translation type="unfinished"/> + <translation>Varovanie: chyba pri ÄÃtanà wallet.dad! VÅ¡etky kľúÄe sú Äitateľné ale transakÄné dáta alebo záznamy v adresári môžu byÅ¥ nesprávne.</translation> </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 type="unfinished"/> + <translation>Varovanie: wallet.dat je poÅ¡kodený, údaje úspeÅ¡ne zÃskané! Pôvodný wallet.dat uložený ako wallet.{timestamp}.bak v %s; ak váš zostatok alebo transakcie niesu správne, mali by ste súbor obnoviÅ¥ zo zálohy.</translation> </message> <message> <source>(default: 1)</source> - <translation type="unfinished"/> + <translation>(predvolené: 1)</translation> </message> <message> <source>(default: wallet.dat)</source> - <translation type="unfinished"/> + <translation>(predvolené: wallet.dat)</translation> </message> <message> <source><category> can be:</source> @@ -2787,11 +2812,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Attempt to recover private keys from a corrupt wallet.dat</source> - <translation type="unfinished"/> + <translation>Pokus zachrániÅ¥ súkromné kľúÄe z poÅ¡kodeného wallet.dat</translation> </message> <message> <source>Bitcoin Core Daemon</source> - <translation type="unfinished"/> + <translation>Démon Jadro Bitcoin</translation> </message> <message> <source>Block creation options:</source> @@ -2799,7 +2824,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Clear list of wallet transactions (diagnostic tool; implies -rescan)</source> - <translation type="unfinished"/> + <translation>VyÄistiÅ¥ zoznam transakcià peňaženky (diagnostický nástroj; zahŕňa -rescan)</translation> </message> <message> <source>Connect only to the specified node(s)</source> @@ -2807,15 +2832,15 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Connect through SOCKS proxy</source> - <translation type="unfinished"/> + <translation>PripojiÅ¥ cez SOCKS proxy</translation> </message> <message> <source>Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)</source> - <translation type="unfinished"/> + <translation>PripojiÅ¥ ku JSON-RPC na <port> (prednastavené: 8332 alebo testnet: 18332)</translation> </message> <message> <source>Connection options:</source> - <translation type="unfinished"/> + <translation>Možnosti pripojenia:</translation> </message> <message> <source>Corrupted block database detected</source> @@ -2823,19 +2848,19 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Debugging/Testing options:</source> - <translation type="unfinished"/> + <translation>Možnosti ladenia/testovania:</translation> </message> <message> <source>Disable safemode, override a real safe mode event (default: 0)</source> - <translation type="unfinished"/> + <translation>Vypnúť bezpeÄný režim, vypnúť udalosÅ¥ skutoÄný bezpeÄný režim (prednastavené: 0)</translation> </message> <message> <source>Discover own IP address (default: 1 when listening and no -externalip)</source> - <translation type="unfinished"/> + <translation>Zisti vlastnú IP adresu (predvolené: 1 pri poÄúvanÃ/listening a žiadnej -externalip)</translation> </message> <message> <source>Do not load the wallet and disable wallet RPC calls</source> - <translation type="unfinished"/> + <translation>Nenahrat peňaženku a zablokovaÅ¥ volania RPC.</translation> </message> <message> <source>Do you want to rebuild the block database now?</source> @@ -2847,7 +2872,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Error initializing wallet database environment %s!</source> - <translation type="unfinished"/> + <translation>Chyba spustenia databázového prostredia peňaženky %s!</translation> </message> <message> <source>Error loading block database</source> @@ -2871,7 +2896,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> - <translation type="unfinished"/> + <translation>Chyba poÄúvania na ktoromkoľvek porte. Použi -listen=0 ak toto chcete.</translation> </message> <message> <source>Failed to read block info</source> @@ -2883,11 +2908,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Failed to sync block index</source> - <translation type="unfinished"/> + <translation>Zlyhalo synchronizovanie zoznamu blokov</translation> </message> <message> <source>Failed to write block index</source> - <translation type="unfinished"/> + <translation>Zlyhalo zapisovanie do zoznamu blokov</translation> </message> <message> <source>Failed to write block info</source> @@ -2899,19 +2924,19 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Failed to write file info</source> - <translation type="unfinished"/> + <translation>Zlyhalo zapisovanie informácié o súbore</translation> </message> <message> <source>Failed to write to coin database</source> - <translation type="unfinished"/> + <translation>Zlyhalo zapisovanie do databázy coins</translation> </message> <message> <source>Failed to write transaction index</source> - <translation type="unfinished"/> + <translation>Zlyhal zápis zoznamu transakciÃ</translation> </message> <message> <source>Failed to write undo data</source> - <translation type="unfinished"/> + <translation>Zlyhalo zapisovanie </translation> </message> <message> <source>Fee per kB to add to transactions you send</source> @@ -2919,87 +2944,87 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Fees smaller than this are considered zero fee (for relaying) (default:</source> - <translation type="unfinished"/> + <translation>Poplatky menÅ¡ie než toto sa považujú za nulové (pre preposielanie) (prednastavené:</translation> </message> <message> <source>Find peers using DNS lookup (default: 1 unless -connect)</source> - <translation type="unfinished"/> + <translation>NájsÅ¥ poÄÃtaÄe v bitcoin sieti použitÃm DNS vyhľadávania (predvolené: 1 okrem -connect)</translation> </message> <message> <source>Force safe mode (default: 0)</source> - <translation type="unfinished"/> + <translation>VnútiÅ¥ bezpeÄný režim (prenastavené: 0)</translation> </message> <message> <source>Generate coins (default: 0)</source> - <translation type="unfinished"/> + <translation>VytváraÅ¥ mince (predvolené: 0)</translation> </message> <message> <source>How many blocks to check at startup (default: 288, 0 = all)</source> - <translation type="unfinished"/> + <translation>Koľko blokov skontrolovaÅ¥ pri spustenà (predvolené: 288, 0 = vÅ¡etky)</translation> </message> <message> <source>If <category> is not supplied, output all debugging information.</source> - <translation type="unfinished"/> + <translation>Ak nie je uvedená <category>, na výstupe zobrazuj vÅ¡etky informácie pre ladenie.</translation> </message> <message> <source>Importing...</source> - <translation type="unfinished"/> + <translation>Prebieha import ...</translation> </message> <message> <source>Incorrect or no genesis block found. Wrong datadir for network?</source> - <translation type="unfinished"/> + <translation>Nesprávny alebo žiadny genesis blok nájdený. Nesprávny dátový prieÄinok alebo sieÅ¥?</translation> </message> <message> <source>Invalid -onion address: '%s'</source> - <translation type="unfinished"/> + <translation>Neplatná -onion adresa: '%s'</translation> </message> <message> <source>Not enough file descriptors available.</source> - <translation type="unfinished"/> + <translation>Nedostatok kľúÄových slov súboru.</translation> </message> <message> <source>Prepend debug output with timestamp (default: 1)</source> - <translation type="unfinished"/> + <translation>Na zaÄiatok logu pre ladenie vlož dátum a Äas (prednastavené: 1)</translation> </message> <message> <source>RPC client options:</source> - <translation type="unfinished"/> + <translation>Možnosti klienta RPC banÃk pyÄo:</translation> </message> <message> <source>Rebuild block chain index from current blk000??.dat files</source> - <translation type="unfinished"/> + <translation>Znovu vytvoriÅ¥ zoznam blokov zo súÄasných blk000??.dat súborov</translation> </message> <message> <source>Select SOCKS version for -proxy (4 or 5, default: 5)</source> - <translation type="unfinished"/> + <translation>Zvoľte SOCKS verziu -proxy (4 alebo 5, predvolené 5)</translation> </message> <message> <source>Set database cache size in megabytes (%d to %d, default: %d)</source> - <translation type="unfinished"/> + <translation>NastaviÅ¥ veľkosÅ¥ pomocnej pamäti databázy v megabajtoch (%d na %d, prednatavené: %d)</translation> </message> <message> <source>Set maximum block size in bytes (default: %d)</source> - <translation type="unfinished"/> + <translation>NastaviÅ¥ najväÄÅ¡iu veľkosÅ¥ bloku v bytoch (predvolené: %d)</translation> </message> <message> <source>Set the number of threads to service RPC calls (default: 4)</source> - <translation type="unfinished"/> + <translation>NastaviÅ¥ množstvo vlákien na obsluhu RPC volanà (predvolené: 4)</translation> </message> <message> <source>Specify wallet file (within data directory)</source> - <translation type="unfinished"/> + <translation>OznaÄ súbor peňaženky (v prieÄinku s dátami)</translation> </message> <message> <source>Spend unconfirmed change when sending transactions (default: 1)</source> - <translation type="unfinished"/> + <translation>MÃňaÅ¥ nepotvrdený výdavok pri odosielanà (prednastavené: 1)</translation> </message> <message> <source>This is intended for regression testing tools and app development.</source> - <translation type="unfinished"/> + <translation>Toto je mienené nástrojom pre regresné testovania a vývoj programu.</translation> </message> <message> <source>Usage (deprecated, use bitcoin-cli):</source> - <translation type="unfinished"/> + <translation>Použitie (neodporúÄa sa, použite bitcoin-cli):</translation> </message> <message> <source>Verifying blocks...</source> @@ -3011,11 +3036,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Wait for RPC server to start</source> - <translation type="unfinished"/> + <translation>ÄŒakanie na Å¡tart RPC servra</translation> </message> <message> <source>Wallet %s resides outside data directory %s</source> - <translation type="unfinished"/> + <translation>Peňaženka %s sa nachádza mimo dátového prieÄinka %s </translation> </message> <message> <source>Wallet options:</source> @@ -3023,11 +3048,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Warning: Deprecated argument -debugnet ignored, use -debug=net</source> - <translation type="unfinished"/> + <translation>Varovanie: Zastaralý parameter -debugnet bol ignorovaný, použite -debug=net</translation> </message> <message> <source>You need to rebuild the database using -reindex to change -txindex</source> - <translation type="unfinished"/> + <translation>Potrebujete prebudovaÅ¥ databázu použitÃm -reindex zmeniÅ¥ -txindex</translation> </message> <message> <source>Imports blocks from external blk000??.dat file</source> @@ -3035,19 +3060,19 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running.</source> - <translation type="unfinished"/> + <translation>Neviem uzamknúť data adresár %s. Jadro Bitcoin je pravdepodobne už spustené.</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>VykonaÅ¥ prÃkaz keÄ po prijatà patriÄné varovanie alebo vidÃme veľmi dlhé rozdvojenie siete (%s v cmd je nahradené správou)</translation> </message> <message> <source>Output debugging information (default: 0, supplying <category> is optional)</source> - <translation type="unfinished"/> + <translation>Výstup informácià pre ladenie (prednastavené: 0, uvádzanie <category> je voliteľné)</translation> </message> <message> <source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source> - <translation type="unfinished"/> + <translation>NastaviÅ¥ najväÄÅ¡iu veľkosÅ¥ vysoká-dôležitosÅ¥/nÃzke-poplatky transakcià v bajtoch (prednastavené: %d)</translation> </message> <message> <source>Information</source> @@ -3055,67 +3080,67 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Invalid amount for -minrelaytxfee=<amount>: '%s'</source> - <translation type="unfinished"/> + <translation>Neplatná suma pre -minrelaytxfee=<amount>: '%s'</translation> </message> <message> <source>Invalid amount for -mintxfee=<amount>: '%s'</source> - <translation type="unfinished"/> + <translation>Neplatná suma pre -mintxfee=<amount>: '%s'</translation> </message> <message> <source>Limit size of signature cache to <n> entries (default: 50000)</source> - <translation type="unfinished"/> + <translation>ObmedziÅ¥ veľkosÅ¥ pomocnej pamäti pre podpisy na <n> vstupov (prednastavené: 50000)</translation> </message> <message> <source>Log transaction priority and fee per kB when mining blocks (default: 0)</source> - <translation type="unfinished"/> + <translation>ZaznamenávaÅ¥ dôležitosÅ¥ transakcià a poplatky za kB ak hľadáme bloky (prednastavené: 0)</translation> </message> <message> <source>Maintain a full transaction index (default: 0)</source> - <translation type="unfinished"/> + <translation>Udržiavaj úplný zoznam transakcià (prednastavené: 0)</translation> </message> <message> <source>Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)</source> - <translation type="unfinished"/> + <translation>Maximálna veľkosÅ¥ prijÃmacieho zásobnÃka pre jedno spojenie, <n>*1000 bytov (predvolené: 5000)</translation> </message> <message> <source>Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)</source> - <translation type="unfinished"/> + <translation>Maximálna veľkosÅ¥ vysielacieho zásobnÃka pre jedno spojenie, <n>*1000 bytov (predvolené: 1000)</translation> </message> <message> <source>Only accept block chain matching built-in checkpoints (default: 1)</source> - <translation type="unfinished"/> + <translation>Akceptuj iba kontrolné body zhodné s blockchain (prednastavené: 1)</translation> </message> <message> <source>Only connect to nodes in network <net> (IPv4, IPv6 or Tor)</source> - <translation type="unfinished"/> + <translation>PripájaÅ¥ sa len k nódam v sieti <net> (IPv4, IPv6 alebo Tor)</translation> </message> <message> <source>Print block on startup, if found in block index</source> - <translation type="unfinished"/> + <translation>VytlaÄ blok pri spustenÃ, ak nájdený v zozname blokov</translation> </message> <message> <source>Print block tree on startup (default: 0)</source> - <translation type="unfinished"/> + <translation>VytlaÄiÅ¥ strom blokov pri spustenà (prednastavené: 0)</translation> </message> <message> <source>RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source> - <translation type="unfinished"/> + <translation>Možnosti RPC SSL: (Pozri v Bitcoin Wiki pokyny pre SSL nastavenie)</translation> </message> <message> <source>RPC server options:</source> - <translation type="unfinished"/> + <translation>Možnosti servra RPC:</translation> </message> <message> <source>Randomly drop 1 of every <n> network messages</source> - <translation type="unfinished"/> + <translation>Náhodne zahadzuj 1 z každých <n> sieÅ¥ových správ</translation> </message> <message> <source>Randomly fuzz 1 of every <n> network messages</source> - <translation type="unfinished"/> + <translation>Náhodne premieÅ¡aj 1 z každých <n> sieÅ¥ových správ</translation> </message> <message> <source>Run a thread to flush wallet periodically (default: 1)</source> - <translation type="unfinished"/> + <translation>MaÅ¥ spustené vlákno pravidelného ÄÃstenia peňaženky (predvolené: 1)</translation> </message> <message> <source>SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source> @@ -3123,7 +3148,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Send command to Bitcoin Core</source> - <translation type="unfinished"/> + <translation>PoslaÅ¥ prÃkaz Jadru Bitcoin</translation> </message> <message> <source>Send trace/debug info to console instead of debug.log file</source> @@ -3131,23 +3156,23 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Set minimum block size in bytes (default: 0)</source> - <translation type="unfinished"/> + <translation>NastaviÅ¥ minimálnu veľkosÅ¥ bloku v bytoch (predvolené: 0)</translation> </message> <message> <source>Sets the DB_PRIVATE flag in the wallet db environment (default: 1)</source> - <translation type="unfinished"/> + <translation>Nastavà DB_PRIVATE možnosÅ¥ v db prostredà peňaženky (prednastavené: 1)</translation> </message> <message> <source>Show all debugging options (usage: --help -help-debug)</source> - <translation type="unfinished"/> + <translation>ZobraziÅ¥ vÅ¡etky možnosti ladenia (použitie: --help --help-debug)</translation> </message> <message> <source>Show benchmark information (default: 0)</source> - <translation type="unfinished"/> + <translation>ZobraziÅ¥ porovnávacie informácie (prednastavené: 0)</translation> </message> <message> <source>Shrink debug.log file on client startup (default: 1 when no -debug)</source> - <translation type="unfinished"/> + <translation>ZmenÅ¡iÅ¥ debug.log pri spustenà klienta (predvolené: 1 ak bez -debug)</translation> </message> <message> <source>Signing transaction failed</source> @@ -3159,7 +3184,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Start Bitcoin Core Daemon</source> - <translation type="unfinished"/> + <translation>Å tart služby Jadro Bitcoin</translation> </message> <message> <source>System error: </source> @@ -3171,7 +3196,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Transaction amounts must be positive</source> - <translation type="unfinished"/> + <translation>Hodnoty transakcie musia byÅ¥ väÄÅ¡ie ako nula (pozitÃvne)</translation> </message> <message> <source>Transaction too large</source> @@ -3199,11 +3224,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Zapping all transactions from wallet...</source> - <translation type="unfinished"/> + <translation>ZmazaÅ¥ vÅ¡etky transakcie z peňaženky...</translation> </message> <message> <source>on startup</source> - <translation type="unfinished"/> + <translation>pri Å¡tarte</translation> </message> <message> <source>version</source> @@ -3259,7 +3284,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Unable to bind to %s on this computer (bind returned error %d, %s)</source> - <translation type="unfinished"/> + <translation>Nepodarilo sa spojiÅ¥ s %s na tomto poÄÃtaÄi (bind vrátil chybu %d, %s)</translation> </message> <message> <source>Allow DNS lookups for -addnode, -seednode and -connect</source> @@ -3291,19 +3316,19 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> - <translation type="unfinished"/> + <translation>Neznáma sieÅ¥ upresnená v -onlynet: '%s'</translation> </message> <message> <source>Unknown -socks proxy version requested: %i</source> - <translation type="unfinished"/> + <translation>Neznáma verzia -socks proxy požadovaná: %i</translation> </message> <message> <source>Cannot resolve -bind address: '%s'</source> - <translation type="unfinished"/> + <translation>Nemožno rozrieÅ¡iÅ¥ -bind adress: '%s'</translation> </message> <message> <source>Cannot resolve -externalip address: '%s'</source> - <translation type="unfinished"/> + <translation>Nemožno rozrieÅ¡iÅ¥ -externalip address: '%s'</translation> </message> <message> <source>Invalid amount for -paytxfee=<amount>: '%s'</source> diff --git a/src/qt/locale/bitcoin_sl_SI.ts b/src/qt/locale/bitcoin_sl_SI.ts index b966842d85..2ad31e911b 100644 --- a/src/qt/locale/bitcoin_sl_SI.ts +++ b/src/qt/locale/bitcoin_sl_SI.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="sl_SI" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="sl_SI" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -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> @@ -1043,6 +1043,14 @@ Naslov: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1136,7 +1144,7 @@ Naslov: %4 </message> <message> <source>User Interface &language:</source> - <translation type="unfinished"/> + <translation>Vmesnik uporabnika &jezik:</translation> </message> <message> <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin.</source> @@ -1344,7 +1352,7 @@ Naslov: %4 <translation>Napaka: Neveljavna kombinacija -regtest and -testnet</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> @@ -1479,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 <b>Ctrl-L</b> to clear screen.</source> - <translation type="unfinished"/> + <translation>Uporabi puÅ¡Äice za gor in dol za navigacijo po zgodovini in <b>Ctrl-L</b> za izbris izpisa na ekranu.</translation> </message> <message> <source>Type <b>help</b> for an overview of available commands.</source> @@ -1839,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> @@ -2618,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> @@ -2630,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> @@ -3260,11 +3268,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3288,27 +3296,27 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <source>Invalid -proxy address: '%s'</source> - <translation type="unfinished"/> + <translation>Neveljaven -proxy naslov: '%s'</translation> </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> - <translation type="unfinished"/> + <translation>Neznano omrežje doloÄeno v -onlynet: '%s'.</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: '%s'</source> - <translation type="unfinished"/> + <translation>NemogoÄe reÅ¡iti -bind naslova: '%s'</translation> </message> <message> <source>Cannot resolve -externalip address: '%s'</source> - <translation type="unfinished"/> + <translation>NemogoÄe reÅ¡iti -externalip naslova: '%s'</translation> </message> <message> <source>Invalid amount for -paytxfee=<amount>: '%s'</source> - <translation type="unfinished"/> + <translation>Neveljavna koliÄina za -paytxfee=<amount>: '%s'</translation> </message> <message> <source>Invalid amount</source> @@ -3336,7 +3344,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3348,7 +3356,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" 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> @@ -3358,7 +3366,9 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <source>You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions.</source> - <translation type="unfinished"/> + <translation>Potrebno je nastaviti rpcpassword=<password> 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_sq.ts b/src/qt/locale/bitcoin_sq.ts index 5d9e7b7168..65e37ff903 100644 --- a/src/qt/locale/bitcoin_sq.ts +++ b/src/qt/locale/bitcoin_sq.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="sq" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="sq" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts index 6549c53542..901eb59394 100644 --- a/src/qt/locale/bitcoin_sr.ts +++ b/src/qt/locale/bitcoin_sr.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="sr" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="sr" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index 27a8c4d0e3..e98048e925 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="sv" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="sv" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1049,6 +1049,14 @@ Adress: %4 <translation>Proxyns IP-adress (t.ex. 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>Tredjeparts URL:er (t.ex. en block utforskare) som finns i transaktionstabben som ett menyval i sammanhanget. %s i URL:en ersätts med tansaktionshashen. Flera URL:er är separerade med vertikala streck |.</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>Tredjeparts transaktions-URL:er</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Aktiva kommandoradsalternativ som överrider alternativen ovan:</translation> </message> @@ -1350,8 +1358,8 @@ Adress: %4 <translation>Fel: Felaktig kombination av -regtest och -testnet.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> - <translation>Bitcoin Core avslutades säkert...</translation> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>Bitcoin Core avslutades inte ännu säkert...</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> diff --git a/src/qt/locale/bitcoin_th_TH.ts b/src/qt/locale/bitcoin_th_TH.ts index a26a128d93..54e15a75e0 100644 --- a/src/qt/locale/bitcoin_th_TH.ts +++ b/src/qt/locale/bitcoin_th_TH.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="th_TH" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="th_TH" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -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>&Delete</source> - <translation>ลบ</translation> + <translation>&ลบ</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.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>.</source> - <translation type="unfinished"/> + <translation>ใส่รหัสผ่านใหม่ให้à¸à¸±à¸šà¸à¸£à¸°à¹€à¸›à¹‹à¸²à¹€à¸‡à¸´à¸™. <br/> à¸à¸£à¸¸à¸“าใช้รหัสผ่านขà¸à¸‡ <b> 10 หรืà¸à¹à¸šà¸šà¸ªà¸¸à¹ˆà¸¡à¸¡à¸²à¸à¸à¸§à¹ˆà¸²à¸•à¸±à¸§à¸à¸±à¸à¸©à¸£ </ b> หรืภ<b> à¹à¸›à¸”หรืà¸à¸¡à¸²à¸à¸à¸§à¹ˆà¸²à¸„ำ </ b></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>&Overview</source> - <translation type="unfinished"/> + <translation>&ภาพรวม</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>&Transactions</source> - <translation type="unfinished"/> + <translation>&à¸à¸²à¸£à¸—ำรายà¸à¸²à¸£</translation> </message> <message> <source>Browse transaction history</source> - <translation type="unfinished"/> + <translation>เรียà¸à¸”ูประวัติà¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡</translation> </message> <message> <source>E&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 &Qt</source> @@ -304,7 +304,7 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&Options...</source> - <translation type="unfinished"/> + <translation>&ตัวเลืà¸à¸...</translation> </message> <message> <source>&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>&Debug window</source> @@ -404,23 +404,23 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <source>&File</source> - <translation type="unfinished"/> + <translation>&ไฟล์</translation> </message> <message> <source>&Settings</source> - <translation type="unfinished"/> + <translation>&à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า</translation> </message> <message> <source>&Help</source> - <translation type="unfinished"/> + <translation>&ช่วยเหลืà¸</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 <b>encrypted</b> and currently <b>unlocked</b></source> - <translation type="unfinished"/> + <translation>ระเป๋าเงินถูภ<b>เข้ารหัส</b> à¹à¸¥à¸°à¹ƒà¸™à¸‚ณะนี้ <b>ปลดล็à¸à¸„à¹à¸¥à¹‰à¸§</b></translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished"/> + <translation>à¸à¸£à¸°à¹€à¸›à¹‹à¸²à¹€à¸‡à¸´à¸™à¸–ูภ<b>เข้ารหัส</b> à¹à¸¥à¸°à¹ƒà¸™à¸›à¸±à¸ˆà¸ˆà¸¸à¸šà¸±à¸™ <b>ล็à¸à¸„ </b></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>&Label</source> - <translation type="unfinished"/> + <translation>&ชื่à¸</translation> </message> <message> <source>The label associated with this address list entry</source> @@ -813,27 +813,27 @@ Address: %4 </message> <message> <source>&Address</source> - <translation type="unfinished"/> + <translation>&ที่à¸à¸¢à¸¹à¹ˆ</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 "%1" is already in the address book.</source> - <translation type="unfinished"/> + <translation>ป้à¸à¸™à¸—ี่à¸à¸¢à¸¹à¹ˆ "%1" ที่มีà¸à¸¢à¸¹à¹ˆà¹à¸¥à¹‰à¸§à¹ƒà¸™à¸ªà¸¡à¸¸à¸”ที่à¸à¸¢à¸¹à¹ˆ</translation> </message> <message> <source>The entered address "%1" 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>&Main</source> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1199,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> @@ -1243,7 +1251,7 @@ Address: %4 </message> <message> <source><b>Recent transactions</b></source> - <translation type="unfinished"/> + <translation><b>รายà¸à¸²à¸£à¸—ำธุรà¸à¸£à¸£à¸¡à¸¥à¹ˆà¸²à¸ªà¸¸à¸”</b></translation> </message> <message> <source>out of sync</source> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> @@ -1687,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> @@ -2119,7 +2127,7 @@ Address: %4 </message> <message> <source>[testnet]</source> - <translation type="unfinished"/> + <translation>[testnet]</translation> </message> </context> <context> @@ -2486,7 +2494,7 @@ Address: %4 </message> <message> <source>Comma separated file (*.csv)</source> - <translation type="unfinished"/> + <translation>คั่นไฟล์ด้วยเครื่à¸à¸‡à¸«à¸¡à¸²à¸¢à¸ˆà¸¸à¸¥à¸ าค (*.csv)</translation> </message> <message> <source>Confirmed</source> @@ -2536,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_tr.ts b/src/qt/locale/bitcoin_tr.ts index 07d6e68f17..15ec92f982 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="tr" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="tr" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1048,6 +1048,14 @@ Adres: %4 <translation>Vekil sunucusunun IP adresi (mesela 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>Muameleler sekmesinde baÄŸlam menüsü unsurları olarak görünen üçüncü taraf baÄŸlantıları (mesela bir blok tarayıcısı). URL'deki %s, muamele hash deÄŸeri ile deÄŸiÅŸtirilecektir. Birden çok baÄŸlantılar düşey çubuklar | ile ayrılacaktır.</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>Üçüncü taraf muamele URL'leri</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>Yukarıdaki seçeneklerin yerine geçen faal komut satırı seçenekleri:</translation> </message> @@ -1349,7 +1357,7 @@ Adres: %4 <translation>Hata: -regtest ve -testnet'in geçersiz kombinasyonu.</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation>Bitcoin ÇekirdeÄŸi henüz güvenli bir ÅŸekilde çıkış yapmamıştır...</translation> </message> <message> diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts index d78775319f..1e739395a2 100644 --- a/src/qt/locale/bitcoin_uk.ts +++ b/src/qt/locale/bitcoin_uk.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="uk" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="uk" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1048,6 +1048,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1349,7 +1357,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_ur_PK.ts b/src/qt/locale/bitcoin_ur_PK.ts index 45b46e2689..d9634f63e3 100644 --- a/src/qt/locale/bitcoin_ur_PK.ts +++ b/src/qt/locale/bitcoin_ur_PK.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="ur_PK" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="ur_PK" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_uz@Cyrl.ts b/src/qt/locale/bitcoin_uz@Cyrl.ts index e4ce310e20..6ba4f6fa1b 100644 --- a/src/qt/locale/bitcoin_uz@Cyrl.ts +++ b/src/qt/locale/bitcoin_uz@Cyrl.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="uz@Cyrl" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="uz@Cyrl" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_vi.ts b/src/qt/locale/bitcoin_vi.ts index 88e37b5ea2..0f9fc4f0f1 100644 --- a/src/qt/locale/bitcoin_vi.ts +++ b/src/qt/locale/bitcoin_vi.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="vi" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="vi" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_vi_VN.ts b/src/qt/locale/bitcoin_vi_VN.ts index 743e7119d1..2102729523 100644 --- a/src/qt/locale/bitcoin_vi_VN.ts +++ b/src/qt/locale/bitcoin_vi_VN.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="vi_VN" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="vi_VN" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index a8859892d6..b87d27fe12 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="zh_CN" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="zh_CN" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -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> @@ -1049,6 +1049,14 @@ Address: %4 <translation>代ç†çš„ IP åœ°å€ (例如 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>出现在交易的选项å¡çš„上下文èœå•é¡¹çš„ç¬¬ä¸‰æ–¹ç½‘å€ (例如:区å—链接查询) 。 %sçš„URL被替æ¢ä¸ºäº¤æ˜“哈希。多个的URL需è¦ç«–线 | 分隔。</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>第三方交易网å€</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>有效的命令行å‚数覆盖上述选项:</translation> </message> @@ -1066,7 +1074,7 @@ Address: %4 </message> <message> <source>(0 = auto, <0 = leave that many cores free)</source> - <translation type="unfinished"/> + <translation>(0 = 自动, <0 = 离开很多å…è´¹çš„æ ¸å¿ƒ)</translation> </message> <message> <source>W&allet</source> @@ -1078,7 +1086,7 @@ Address: %4 </message> <message> <source>Enable coin &control features</source> - <translation type="unfinished"/> + <translation>å¯åŠ¨è´§å¸ &控制功能</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> @@ -1086,7 +1094,7 @@ Address: %4 </message> <message> <source>&Spend unconfirmed change</source> - <translation type="unfinished"/> + <translation>&选择未ç»ç¡®è®¤çš„花费</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> @@ -1343,15 +1351,15 @@ 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> <translation>é”™è¯¯ï¼šæ— æ•ˆçš„ -regtest 与 -testnet 结åˆä½“。</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> - <translation type="unfinished"/> + <source>Bitcoin Core didn't yet exit safely...</source> + <translation>比特å¸æ ¸å¿ƒé’±åŒ…没有安全退出....</translation> </message> <message> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> @@ -2659,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> @@ -2714,7 +2722,7 @@ rpcpassword=%s </message> <message> <source>Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:15)</source> - <translation type="unfinished"/> + <translation>自由交易ä¸æ–的速率é™åˆ¶ä¸º<n>*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> @@ -2726,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> @@ -2742,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 <n> megabytes (default: 100)</source> - <translation type="unfinished"/> + <translation>ä»Žç¼“å†²æ± æ¸…ç†ç£ç›˜æ•°æ®åº“活动日志æ¯<n>å…†å—节 (默认值: 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, <0 = leave that many cores free, default: %d)</source> - <translation type="unfinished"/> + <translation>设置脚本验è¯çš„ç¨‹åº (%u 到 %d, 0 = 自动, <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> @@ -2770,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> @@ -2802,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><category> can be:</source> @@ -2842,7 +2850,7 @@ rpcpassword=%s </message> <message> <source>Connection options:</source> - <translation type="unfinished"/> + <translation>连接选项:</translation> </message> <message> <source>Corrupted block database detected</source> @@ -2850,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> @@ -2946,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> @@ -2954,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> @@ -3002,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> @@ -3062,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> @@ -3090,11 +3098,11 @@ rpcpassword=%s </message> <message> <source>Limit size of signature cache to <n> entries (default: 50000)</source> - <translation type="unfinished"/> + <translation>ç¾å缓冲大å°é™åˆ¶æ¯<n> æ¡ç›® (默认值: 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> @@ -3118,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> @@ -3134,15 +3142,15 @@ rpcpassword=%s </message> <message> <source>Randomly drop 1 of every <n> network messages</source> - <translation type="unfinished"/> + <translation>éšæœºæ¯1个丢失测试<n>网络信æ¯</translation> </message> <message> <source>Randomly fuzz 1 of every <n> network messages</source> - <translation type="unfinished"/> + <translation>éšæœºæ¯1个模拟测试<n>网络信æ¯</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> @@ -3150,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> @@ -3162,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> @@ -3186,7 +3194,7 @@ rpcpassword=%s </message> <message> <source>Start Bitcoin Core Daemon</source> - <translation type="unfinished"/> + <translation>å¼€å¯æ¯”特å¸æ ¸å¿ƒé’±åŒ…守护进程</translation> </message> <message> <source>System error: </source> @@ -3230,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/locale/bitcoin_zh_HK.ts b/src/qt/locale/bitcoin_zh_HK.ts index cf729a3f92..835d0134d6 100644 --- a/src/qt/locale/bitcoin_zh_HK.ts +++ b/src/qt/locale/bitcoin_zh_HK.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="zh_HK" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="zh_HK" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1039,6 +1039,14 @@ Address: %4 <translation type="unfinished"/> </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"/> + </message> + <message> + <source>Third party transaction URLs</source> + <translation type="unfinished"/> + </message> + <message> <source>Active command-line options that override above options:</source> <translation type="unfinished"/> </message> @@ -1340,7 +1348,7 @@ Address: %4 <translation type="unfinished"/> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation type="unfinished"/> </message> <message> diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts index 4f7561ab9e..fccdf48abd 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><!DOCTYPE TS><TS language="zh_TW" version="2.0"> +<?xml version="1.0" ?><!DOCTYPE TS><TS language="zh_TW" version="2.1"> <context> <name>AboutDialog</name> <message> @@ -1050,6 +1050,14 @@ Address: %4 <translation>代ç†ä¼ºæœå™¨çš„網際網路ä½å€(åƒæ˜¯ 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>在交易é 籤的情境é¸å–®å‡ºç¾çš„第三方(比如說å€å¡ŠæŽ¢ç´¢ç¶²ç«™)網å€é€£çµã€‚網å€ä¸çš„ %s 會被å–代為交易的雜湊值。å¯ä»¥ç”¨ç›´ç·šç¬¦è™Ÿ | 來分隔多個連çµã€‚</translation> + </message> + <message> + <source>Third party transaction URLs</source> + <translation>交易的第三方網å€é€£çµ</translation> + </message> + <message> <source>Active command-line options that override above options:</source> <translation>從命令列å–代掉以上è¨å®šçš„é¸é …有:</translation> </message> @@ -1351,7 +1359,7 @@ Address: %4 <translation>錯誤: -regtest å’Œ -testnet 的使用組åˆç„¡æ•ˆã€‚</translation> </message> <message> - <source>Bitcoin Core did't yet exit safely...</source> + <source>Bitcoin Core didn't yet exit safely...</source> <translation>ä½å…ƒå¹£æ ¸å¿ƒé‚„沒有安全地çµæŸ...</translation> </message> <message> 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 311563d946..f51b0311bc 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, false, BitcoinUnits::separatorAlways, true)); ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance, false, BitcoinUnits::separatorAlways, true)); ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, immatureBalance, false, BitcoinUnits::separatorAlways, true)); ui->labelTotal->setText(BitcoinUnits::formatWithUnit(unit, balance + unconfirmedBalance + immatureBalance, false, BitcoinUnits::separatorAlways, true)); + ui->labelWatchAvailable->setText(BitcoinUnits::formatWithUnit(unit, watchOnlyBalance, false, BitcoinUnits::separatorAlways, true)); + ui->labelWatchPending->setText(BitcoinUnits::formatWithUnit(unit, watchUnconfBalance, false, BitcoinUnits::separatorAlways, true)); + ui->labelWatchImmature->setText(BitcoinUnits::formatWithUnit(unit, watchImmatureBalance, false, BitcoinUnits::separatorAlways, true)); + ui->labelWatchTotal->setText(BitcoinUnits::formatWithUnit(unit, watchOnlyBalance + watchUnconfBalance + watchImmatureBalance, false, BitcoinUnits::separatorAlways, true)); // 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/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 3ccfb429a6..f2c76c8355 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -5,21 +5,21 @@ #include "receivecoinsdialog.h" #include "ui_receivecoinsdialog.h" -#include "walletmodel.h" -#include "bitcoinunits.h" #include "addressbookpage.h" -#include "optionsmodel.h" +#include "addresstablemodel.h" +#include "bitcoinunits.h" #include "guiutil.h" +#include "optionsmodel.h" #include "receiverequestdialog.h" -#include "addresstablemodel.h" #include "recentrequeststablemodel.h" +#include "walletmodel.h" #include <QAction> #include <QCursor> +#include <QItemSelection> #include <QMessageBox> -#include <QTextDocument> #include <QScrollBar> -#include <QItemSelection> +#include <QTextDocument> ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget *parent) : QDialog(parent), @@ -78,7 +78,7 @@ void ReceiveCoinsDialog::setModel(WalletModel *model) connect(tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, - SLOT(on_recentRequestsView_selectionChanged(QItemSelection, QItemSelection))); + SLOT(recentRequestsView_selectionChanged(QItemSelection, QItemSelection))); // Last 2 columns are set by the columnResizingFixer, when the table geometry is ready. columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH); } @@ -165,8 +165,7 @@ void ReceiveCoinsDialog::on_recentRequestsView_doubleClicked(const QModelIndex & dialog->show(); } -void ReceiveCoinsDialog::on_recentRequestsView_selectionChanged(const QItemSelection &selected, - const QItemSelection &deselected) +void ReceiveCoinsDialog::recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { // Enable Show/Remove buttons only if anything is selected. bool enable = !ui->recentRequestsView->selectionModel()->selectedRows().isEmpty(); @@ -200,7 +199,7 @@ void ReceiveCoinsDialog::on_removeRequestButton_clicked() // We override the virtual resizeEvent of the QWidget to adjust tables column // sizes as the tables width is proportional to the dialogs width. -void ReceiveCoinsDialog::resizeEvent(QResizeEvent* event) +void ReceiveCoinsDialog::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); columnResizingFixer->stretchColumnWidth(RecentRequestsTableModel::Message); diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index ab63331597..663cb157a4 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -18,8 +18,8 @@ namespace Ui { class ReceiveCoinsDialog; } -class WalletModel; class OptionsModel; +class WalletModel; QT_BEGIN_NAMESPACE class QModelIndex; @@ -57,16 +57,16 @@ private: WalletModel *model; QMenu *contextMenu; void copyColumnToClipboard(int column); - virtual void resizeEvent(QResizeEvent* event); + virtual void resizeEvent(QResizeEvent *event); private slots: void on_receiveButton_clicked(); void on_showRequestButton_clicked(); void on_removeRequestButton_clicked(); void on_recentRequestsView_doubleClicked(const QModelIndex &index); - void on_recentRequestsView_selectionChanged(const QItemSelection &, const QItemSelection &); + void recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); void updateDisplayUnit(); - void showMenu(const QPoint &); + void showMenu(const QPoint &point); void copyLabel(); void copyMessage(); void copyAmount(); 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 Binary files differnew file mode 100644 index 0000000000..ec3497435c --- /dev/null +++ b/src/qt/res/icons/unit_btc.png diff --git a/src/qt/res/icons/unit_mbtc.png b/src/qt/res/icons/unit_mbtc.png Binary files differnew file mode 100644 index 0000000000..32bf2f2ca0 --- /dev/null +++ b/src/qt/res/icons/unit_mbtc.png diff --git a/src/qt/res/icons/unit_ubtc.png b/src/qt/res/icons/unit_ubtc.png Binary files differnew file mode 100644 index 0000000000..d5a154882b --- /dev/null +++ b/src/qt/res/icons/unit_ubtc.png diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index ba5871ae2b..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(); } @@ -271,19 +290,34 @@ void RPCConsole::setClientModel(ClientModel *model) setNumConnections(model->getNumConnections()); connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); - setNumBlocks(model->getNumBlocks(), model->getNumBlocksOfPeers()); - connect(model, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int))); + setNumBlocks(model->getNumBlocks()); + connect(model, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int))); 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())); } } @@ -366,11 +400,9 @@ void RPCConsole::setNumConnections(int count) ui->numberOfConnections->setText(connections); } -void RPCConsole::setNumBlocks(int count, int countOfPeers) +void RPCConsole::setNumBlocks(int count) { ui->numberOfBlocks->setText(QString::number(count)); - // If there is no current countOfPeers available display N/A instead of 0, which can't ever be true - ui->totalBlocks->setText(countOfPeers == 0 ? tr("N/A") : QString::number(countOfPeers)); if(clientModel) ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString()); } @@ -384,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 @@ -476,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) @@ -494,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 f7a7772050..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(); @@ -52,11 +77,15 @@ public slots: /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set number of blocks shown in the UI */ - void setNumBlocks(int count, int countOfPeers); + void setNumBlocks(int count); /** Go forward or back in history */ 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 f432c4add6..25e3d2a0dc 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 0bb93035cc..ac1614efd0 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::formatHtmlWithUnit(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::formatHtmlWithUnit(unit, -txout.nValue) + "<br>"; + if(toSelf) + strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(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::formatHtmlWithUnit(unit, -nValue) + "<br>"; - strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "<br>"; + strHTML += "<b>" + tr("Total debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "<br>"; + strHTML += "<b>" + tr("Total credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(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::formatHtmlWithUnit(unit, -wallet->GetDebit(txin)) + "<br>"; + strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>"; BOOST_FOREACH(const CTxOut& txout, wtx.vout) if (wallet->IsMine(txout)) - strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout)) + "<br>"; + strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(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::formatHtmlWithUnit(unit, -wallet->GetDebit(txin)) + "<br>"; + strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>"; BOOST_FOREACH(const CTxOut& txout, wtx.vout) if(wallet->IsMine(txout)) - strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout)) + "<br>"; + strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(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::formatHtmlWithUnit(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 c0f7edd871..fb21ddc46d 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -129,12 +129,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) @@ -158,7 +158,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 @@ -167,8 +167,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; } } @@ -189,20 +188,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; } } } @@ -221,7 +221,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(""); @@ -234,8 +234,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())); @@ -246,6 +245,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; @@ -362,6 +368,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(); } @@ -387,19 +395,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; } } @@ -534,7 +545,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 9ee375d787..463e7bbff0 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -89,6 +89,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 98914fc2d0..7e8b71d8ea 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -311,7 +311,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(" © 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 1ed8a8e866..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> @@ -64,9 +64,9 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) BOOST_FOREACH(const CTransaction&tx, block.vtx) txs.push_back(tx.GetHash().GetHex()); result.push_back(Pair("tx", txs)); - result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime())); - result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce)); - result.push_back(Pair("bits", HexBits(block.nBits))); + result.push_back(Pair("time", block.GetBlockTime())); + result.push_back(Pair("nonce", (uint64_t)block.nNonce)); + result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); @@ -175,7 +175,7 @@ Value getrawmempool(const Array& params, bool fHelp) Object info; info.push_back(Pair("size", (int)e.GetTxSize())); info.push_back(Pair("fee", ValueFromAmount(e.GetFee()))); - info.push_back(Pair("time", (boost::int64_t)e.GetTime())); + info.push_back(Pair("time", e.GetTime())); info.push_back(Pair("height", (int)e.GetHeight())); info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight()))); info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height()))); @@ -315,11 +315,11 @@ Value gettxoutsetinfo(const Array& params, bool fHelp) CCoinsStats stats; if (pcoinsTip->GetStats(stats)) { - ret.push_back(Pair("height", (boost::int64_t)stats.nHeight)); + ret.push_back(Pair("height", (int64_t)stats.nHeight)); ret.push_back(Pair("bestblock", stats.hashBlock.GetHex())); - ret.push_back(Pair("transactions", (boost::int64_t)stats.nTransactions)); - ret.push_back(Pair("txouts", (boost::int64_t)stats.nTransactionOutputs)); - ret.push_back(Pair("bytes_serialized", (boost::int64_t)stats.nSerializedSize)); + ret.push_back(Pair("transactions", (int64_t)stats.nTransactions)); + ret.push_back(Pair("txouts", (int64_t)stats.nTransactionOutputs)); + ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize)); ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex())); ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount))); } @@ -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 8620a87297..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 ¶m, strParams) - params.push_back(param); - - int n = params.size(); - // - // Special case non-string parameter types - // - if (strMethod == "stop" && n > 0) ConvertTo<bool>(params[0]); - if (strMethod == "getaddednodeinfo" && n > 0) ConvertTo<bool>(params[0]); - if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]); - if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]); - if (strMethod == "getnetworkhashps" && n > 0) ConvertTo<boost::int64_t>(params[0]); - if (strMethod == "getnetworkhashps" && n > 1) ConvertTo<boost::int64_t>(params[1]); - if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]); - if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]); - if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]); - if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]); - if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]); - if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]); - if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]); - if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]); - if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]); - if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]); - if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]); - if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]); - if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]); - if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]); - if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]); - if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]); - if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]); - if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]); - if (strMethod == "getblocktemplate" && n > 0) ConvertTo<Object>(params[0]); - if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]); - if (strMethod == "sendmany" && n > 1) ConvertTo<Object>(params[1]); - if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]); - if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]); - if (strMethod == "addmultisigaddress" && n > 1) ConvertTo<Array>(params[1]); - if (strMethod == "createmultisig" && n > 0) ConvertTo<boost::int64_t>(params[0]); - if (strMethod == "createmultisig" && n > 1) ConvertTo<Array>(params[1]); - if (strMethod == "listunspent" && n > 0) ConvertTo<boost::int64_t>(params[0]); - if (strMethod == "listunspent" && n > 1) ConvertTo<boost::int64_t>(params[1]); - if (strMethod == "listunspent" && n > 2) ConvertTo<Array>(params[2]); - if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]); - if (strMethod == "getrawtransaction" && n > 1) ConvertTo<boost::int64_t>(params[1]); - if (strMethod == "createrawtransaction" && n > 0) ConvertTo<Array>(params[0]); - if (strMethod == "createrawtransaction" && n > 1) ConvertTo<Object>(params[1]); - if (strMethod == "signrawtransaction" && n > 1) ConvertTo<Array>(params[1], true); - if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true); - if (strMethod == "sendrawtransaction" && n > 1) ConvertTo<bool>(params[1], true); - if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]); - if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]); - if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]); - if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]); - if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]); - if (strMethod == "verifychain" && n > 0) ConvertTo<boost::int64_t>(params[0]); - if (strMethod == "verifychain" && n > 1) ConvertTo<boost::int64_t>(params[1]); - if (strMethod == "keypoolrefill" && n > 0) ConvertTo<boost::int64_t>(params[0]); - if (strMethod == "getrawmempool" && n > 0) ConvertTo<bool>(params[0]); + 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 070cf1cb2a..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. @@ -88,7 +62,7 @@ Value GetNetworkHashPS(int lookup, int height) { uint256 workDiff = pb->nChainWork - pb0->nChainWork; int64_t timeDiff = maxTime - minTime; - return (boost::int64_t)(workDiff.getdouble() / timeDiff); + return (int64_t)(workDiff.getdouble() / timeDiff); } Value getnetworkhashps(const Array& params, bool fHelp) @@ -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; @@ -226,8 +197,8 @@ Value gethashespersec(const Array& params, bool fHelp) ); if (GetTimeMillis() - nHPSTimerStart > 8000) - return (boost::int64_t)0; - return (boost::int64_t)dHashesPerSec; + return (int64_t)0; + return (int64_t)dHashesPerSec; } #endif @@ -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 = CBigNum().SetCompact(pblock->nBits).getuint256(); - - 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) { @@ -559,7 +420,7 @@ Value getblocktemplate(const Array& params, bool fHelp) Object aux; aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + uint256 hashTarget = uint256().SetCompact(pblock->nBits); static Array aMutable; if (aMutable.empty()) @@ -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 ae154f2ae4..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) { @@ -69,21 +70,21 @@ Value getinfo(const Array& params, bool fHelp) } #endif obj.push_back(Pair("blocks", (int)chainActive.Height())); - obj.push_back(Pair("timeoffset", (boost::int64_t)GetTimeOffset())); + 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", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); + obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); } if (pwalletMain && pwalletMain->IsCrypted()) - obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime)); - obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); + obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); + 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)) @@ -176,7 +187,7 @@ Value validateaddress(const Array& params, bool fHelp) // // Used by addmultisigaddress / createmultisig: // -CScript _createmultisig(const Array& params) +CScript _createmultisig_redeemScript(const Array& params) { int nRequired = params[0].get_int(); const Array& keys = params[1].get_array(); @@ -187,7 +198,7 @@ CScript _createmultisig(const Array& params) if ((int)keys.size() < nRequired) throw runtime_error( strprintf("not enough keys supplied " - "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired)); + "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired)); std::vector<CPubKey> pubkeys; pubkeys.resize(keys.size()); for (unsigned int i = 0; i < keys.size(); i++) @@ -228,6 +239,11 @@ CScript _createmultisig(const Array& params) } CScript result; result.SetMultisig(nRequired, pubkeys); + + if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) + throw runtime_error( + strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE)); + return result; } @@ -263,7 +279,7 @@ Value createmultisig(const Array& params, bool fHelp) } // Construct using pay-to-script-hash: - CScript inner = _createmultisig(params); + CScript inner = _createmultisig_redeemScript(params); CScriptID innerID = inner.GetID(); CBitcoinAddress address(innerID); diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 573d6cd3f6..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,12 +116,12 @@ 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("lastsend", (boost::int64_t)stats.nLastSend)); - obj.push_back(Pair("lastrecv", (boost::int64_t)stats.nLastRecv)); - obj.push_back(Pair("bytessent", (boost::int64_t)stats.nSendBytes)); - obj.push_back(Pair("bytesrecv", (boost::int64_t)stats.nRecvBytes)); - obj.push_back(Pair("conntime", (boost::int64_t)stats.nTimeConnected)); + obj.push_back(Pair("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)); + obj.push_back(Pair("bytesrecv", stats.nRecvBytes)); + obj.push_back(Pair("conntime", stats.nTimeConnected)); obj.push_back(Pair("pingtime", stats.dPingTime)); if (stats.dPingWait > 0.0) obj.push_back(Pair("pingwait", stats.dPingWait)); @@ -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; } @@ -328,9 +330,9 @@ Value getnettotals(const Array& params, bool fHelp) ); Object obj; - obj.push_back(Pair("totalbytesrecv", static_cast< boost::uint64_t>(CNode::GetTotalBytesRecv()))); - obj.push_back(Pair("totalbytessent", static_cast<boost::uint64_t>(CNode::GetTotalBytesSent()))); - obj.push_back(Pair("timemillis", static_cast<boost::int64_t>(GetTimeMillis()))); + obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv())); + obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent())); + obj.push_back(Pair("timemillis", GetTimeMillis())); return obj; } @@ -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("timeoffset", (boost::int64_t)GetTimeOffset())); + 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 652b14d187..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: %"PRIszu"\r\n" - "Content-Type: application/json\r\n" + "Content-Length: %u\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 8b3df19621..5627077bfb 100644 --- a/src/rpcprotocol.h +++ b/src/rpcprotocol.h @@ -103,11 +103,27 @@ public: } bool connect(const std::string& server, const std::string& port) { - boost::asio::ip::tcp::resolver resolver(stream.get_io_service()); - boost::asio::ip::tcp::resolver::query query(server.c_str(), port.c_str()); - boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); - boost::asio::ip::tcp::resolver::iterator end; + using namespace boost::asio::ip; + tcp::resolver resolver(stream.get_io_service()); + tcp::resolver::iterator endpoint_iterator; +#if BOOST_VERSION >= 104300 + try { +#endif + // The default query (flags address_configured) tries IPv6 if + // non-localhost IPv6 configured, and IPv4 if non-localhost IPv4 + // configured. + tcp::resolver::query query(server.c_str(), port.c_str()); + endpoint_iterator = resolver.resolve(query); +#if BOOST_VERSION >= 104300 + } catch(boost::system::system_error &e) + { + // If we at first don't succeed, try blanket lookup (IPv4+IPv6 independent of configured interfaces) + tcp::resolver::query query(server.c_str(), port.c_str(), resolver_query_base::flags()); + endpoint_iterator = resolver.resolve(query); + } +#endif boost::system::error_code error = boost::asio::error::host_not_found; + tcp::resolver::iterator end; while (error && endpoint_iterator != end) { stream.lowest_layer().close(); @@ -125,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 e86d6808e1..2306b1b883 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -55,7 +55,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) { entry.push_back(Pair("txid", tx.GetHash().GetHex())); entry.push_back(Pair("version", tx.nVersion)); - entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime)); + entry.push_back(Pair("locktime", (int64_t)tx.nLockTime)); Array vin; BOOST_FOREACH(const CTxIn& txin, tx.vin) { @@ -65,13 +65,13 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) else { in.push_back(Pair("txid", txin.prevout.hash.GetHex())); - in.push_back(Pair("vout", (boost::int64_t)txin.prevout.n)); + in.push_back(Pair("vout", (int64_t)txin.prevout.n)); Object o; o.push_back(Pair("asm", txin.scriptSig.ToString())); o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); in.push_back(Pair("scriptSig", o)); } - in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence)); + in.push_back(Pair("sequence", (int64_t)txin.nSequence)); vin.push_back(in); } entry.push_back(Pair("vin", vin)); @@ -81,7 +81,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) const CTxOut& txout = tx.vout[i]; Object out; out.push_back(Pair("value", ValueFromAmount(txout.nValue))); - out.push_back(Pair("n", (boost::int64_t)i)); + out.push_back(Pair("n", (int64_t)i)); Object o; ScriptPubKeyToJSON(txout.scriptPubKey, o, true); out.push_back(Pair("scriptPubKey", o)); @@ -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", (boost::int64_t)pindex->nTime)); - entry.push_back(Pair("blocktime", (boost::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,11 +714,11 @@ 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); } - if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0)) + if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STANDARD_SCRIPT_VERIFY_FLAGS, 0)) fComplete = false; } @@ -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 f78cb420f4..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; @@ -38,6 +38,8 @@ static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers; static ssl::context* rpc_ssl_context = NULL; static boost::thread_group* rpc_worker_group = NULL; static boost::asio::io_service::work *rpc_dummy_work = NULL; +static std::vector<CSubNet> rpc_allow_subnets; //!< List of subnets to allow RPC connections from +static std::vector< boost::shared_ptr<ip::tcp::acceptor> > rpc_acceptors; void RPCTypeCheck(const Array& params, const list<Value_type>& typesExpected, @@ -95,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; @@ -252,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 }, @@ -266,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 */ @@ -287,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 }, @@ -311,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 }; @@ -358,38 +353,36 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) stream << HTTPReply(nStatus, strReply, false) << std::flush; } -bool ClientAllowed(const boost::asio::ip::address& address) +CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address) { + CNetAddr netaddr; // Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses if (address.is_v6() && (address.to_v6().is_v4_compatible() || address.to_v6().is_v4_mapped())) - return ClientAllowed(address.to_v6().to_v4()); - - if (address == asio::ip::address_v4::loopback() - || address == asio::ip::address_v6::loopback() - || (address.is_v4() - // Check whether IPv4 addresses match 127.0.0.0/8 (loopback subnet) - && (address.to_v4().to_ulong() & 0xff000000) == 0x7f000000)) - return true; - - const string strAddress = address.to_string(); - const vector<string>& vAllow = mapMultiArgs["-rpcallowip"]; - BOOST_FOREACH(string strAllow, vAllow) - if (WildcardMatch(strAddress, strAllow)) - return true; - return false; + address = address.to_v6().to_v4(); + + if(address.is_v4()) + { + boost::asio::ip::address_v4::bytes_type bytes = address.to_v4().to_bytes(); + netaddr.SetRaw(NET_IPV4, &bytes[0]); + } + else + { + boost::asio::ip::address_v6::bytes_type bytes = address.to_v6().to_bytes(); + netaddr.SetRaw(NET_IPV6, &bytes[0]); + } + return netaddr; } -class AcceptedConnection +bool ClientAllowed(const boost::asio::ip::address& address) { -public: - virtual ~AcceptedConnection() {} - - virtual std::iostream& stream() = 0; - virtual std::string peer_address_to_string() const = 0; - virtual void close() = 0; -}; + CNetAddr netaddr = BoostAsioToCNetAddr(address); + BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets) + if (subnet.Match(netaddr)) + return true; + return false; +} template <typename Protocol> class AcceptedConnectionImpl : public AcceptedConnection @@ -435,7 +428,7 @@ template <typename Protocol, typename SocketAcceptorService> static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor, ssl::context& context, bool fUseSSL, - AcceptedConnection* conn, + boost::shared_ptr< AcceptedConnection > conn, const boost::system::error_code& error); /** @@ -447,7 +440,7 @@ static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketA const bool fUseSSL) { // Accept connection - AcceptedConnectionImpl<Protocol>* conn = new AcceptedConnectionImpl<Protocol>(acceptor->get_io_service(), context, fUseSSL); + boost::shared_ptr< AcceptedConnectionImpl<Protocol> > conn(new AcceptedConnectionImpl<Protocol>(acceptor->get_io_service(), context, fUseSSL)); acceptor->async_accept( conn->sslStream.lowest_layer(), @@ -457,7 +450,7 @@ static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketA boost::ref(context), fUseSSL, conn, - boost::asio::placeholders::error)); + _1)); } @@ -468,21 +461,20 @@ template <typename Protocol, typename SocketAcceptorService> static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor, ssl::context& context, const bool fUseSSL, - AcceptedConnection* conn, + boost::shared_ptr< AcceptedConnection > conn, const boost::system::error_code& error) { // Immediately start accepting new connections, except when we're cancelled or our socket is closed. if (error != asio::error::operation_aborted && acceptor->is_open()) RPCListen(acceptor, context, fUseSSL); - AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn); + AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn.get()); - // TODO: Actually handle errors if (error) { - delete conn; + // TODO: Actually handle errors + LogPrintf("%s: Error: %s\n", __func__, error.message()); } - // Restrict callers by IP. It is important to // do this before starting client thread, to filter out // certain DoS and misbehaving clients. @@ -490,18 +482,50 @@ 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; - delete conn; + conn->stream() << HTTPError(HTTP_FORBIDDEN, false) << std::flush; + conn->close(); } else { - ServiceConnection(conn); + ServiceConnection(conn.get()); conn->close(); - delete conn; } } +static ip::tcp::endpoint ParseEndpoint(const std::string &strEndpoint, int defaultPort) +{ + std::string addr; + int port = defaultPort; + SplitHostPort(strEndpoint, port, addr); + return ip::tcp::endpoint(asio::ip::address::from_string(addr), port); +} + void StartRPCThreads() { + rpc_allow_subnets.clear(); + rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet + rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost + if (mapMultiArgs.count("-rpcallowip")) + { + const vector<string>& vAllow = mapMultiArgs["-rpcallowip"]; + BOOST_FOREACH(string strAllow, vAllow) + { + CSubNet subnet(strAllow); + if(!subnet.IsValid()) + { + uiInterface.ThreadSafeMessageBox( + 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; + } + rpc_allow_subnets.push_back(subnet); + } + } + std::string strAllowed; + BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets) + strAllowed += subnet.ToString() + " "; + LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed); + strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; if (((mapArgs["-rpcpassword"] == "") || (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword()) @@ -556,56 +580,74 @@ void StartRPCThreads() SSL_CTX_set_cipher_list(rpc_ssl_context->impl(), strCiphers.c_str()); } - // Try a dual IPv6/IPv4 socket, falling back to separate IPv4 and IPv6 sockets - const bool loopback = !mapArgs.count("-rpcallowip"); - asio::ip::address bindAddress = loopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any(); - ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", Params().RPCPort())); - boost::system::error_code v6_only_error; - boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service)); - - bool fListening = false; - std::string strerr; - try + std::vector<ip::tcp::endpoint> vEndpoints; + bool bBindAny = false; + int defaultPort = GetArg("-rpcport", BaseParams().RPCPort()); + if (!mapArgs.count("-rpcallowip")) // Default to loopback if not allowing external IPs { - acceptor->open(endpoint.protocol()); - acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); - - // Try making the socket dual IPv6/IPv4 (if listening on the "any" address) - acceptor->set_option(boost::asio::ip::v6_only(loopback), v6_only_error); - - acceptor->bind(endpoint); - acceptor->listen(socket_base::max_connections); - - RPCListen(acceptor, *rpc_ssl_context, fUseSSL); - - fListening = true; - } - catch(boost::system::system_error &e) + vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v6::loopback(), defaultPort)); + vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v4::loopback(), defaultPort)); + if (mapArgs.count("-rpcbind")) + { + LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n"); + } + } else if (mapArgs.count("-rpcbind")) // Specific bind address { - strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s"), endpoint.port(), e.what()); + BOOST_FOREACH(const std::string &addr, mapMultiArgs["-rpcbind"]) + { + try { + vEndpoints.push_back(ParseEndpoint(addr, defaultPort)); + } + catch(boost::system::system_error &e) + { + uiInterface.ThreadSafeMessageBox( + strprintf(_("Could not parse -rpcbind value %s as network address"), addr), + "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return; + } + } + } else { // No specific bind address specified, bind to any + vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v6::any(), defaultPort)); + vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v4::any(), defaultPort)); + // Prefer making the socket dual IPv6/IPv4 instead of binding + // to both addresses seperately. + bBindAny = true; } - try { - // If dual IPv6/IPv4 failed (or we're opening loopback interfaces only), open IPv4 separately - if (!fListening || loopback || v6_only_error) - { - bindAddress = loopback ? asio::ip::address_v4::loopback() : asio::ip::address_v4::any(); - endpoint.address(bindAddress); + bool fListening = false; + std::string strerr; + BOOST_FOREACH(const ip::tcp::endpoint &endpoint, vEndpoints) + { + asio::ip::address bindAddress = endpoint.address(); + 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)); - acceptor.reset(new ip::tcp::acceptor(*rpc_io_service)); + try { acceptor->open(endpoint.protocol()); acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + + // Try making the socket dual IPv6/IPv4 when listening on the IPv6 "any" address + acceptor->set_option(boost::asio::ip::v6_only( + !bBindAny || bindAddress != asio::ip::address_v6::any()), v6_only_error); + acceptor->bind(endpoint); acceptor->listen(socket_base::max_connections); 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; + } + catch(boost::system::system_error &e) + { + LogPrintf("ERROR: Binding RPC on address %s port %i failed: %s\n", bindAddress.to_string(), endpoint.port(), e.what()); + strerr = strprintf(_("An error occurred while setting up the RPC address %s port %u for listening: %s"), bindAddress.to_string(), endpoint.port(), e.what()); } - } - catch(boost::system::system_error &e) - { - strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv4: %s"), endpoint.port(), e.what()); } if (!fListening) { @@ -636,7 +678,25 @@ void StopRPCThreads() { if (rpc_io_service == NULL) return; + // 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(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(ec); + if (ec) + LogPrintf("%s: Warning: %s when cancelling timer", __func__, ec.message()); + } deadlineTimers.clear(); + rpc_io_service->stop(); if (rpc_worker_group != NULL) rpc_worker_group->join_all(); @@ -693,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 @@ -740,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; @@ -756,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 1092c691be..e32eb975a1 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -19,6 +19,17 @@ #include "json/json_spirit_writer_template.h" 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(); @@ -50,6 +61,9 @@ void RPCTypeCheck(const json_spirit::Object& o, */ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds); +//! Convert boost::asio address to CNetAddr +extern CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address); + typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp); class CRPCCommand @@ -102,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); @@ -118,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); @@ -126,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 a5a7df0867..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", (boost::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,8 +58,12 @@ 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)); - entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime())); - entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived)); + 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) entry.push_back(Pair(item.first, item.second)); } @@ -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"); @@ -871,7 +881,7 @@ Value sendmany(const Array& params, bool fHelp) } // Defined in rpcmisc.cpp -extern CScript _createmultisig(const Array& params); +extern CScript _createmultisig_redeemScript(const Array& params); Value addmultisigaddress(const Array& params, bool fHelp) { @@ -908,7 +918,7 @@ Value addmultisigaddress(const Array& params, bool fHelp) strAccount = AccountFromValue(params[2]); // Construct using pay-to-script-hash: - CScript inner = _createmultisig(params); + CScript inner = _createmultisig_redeemScript(params); CScriptID innerID = inner.GetID(); pwalletMain->AddCScript(inner); @@ -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()) @@ -1167,7 +1206,7 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Ar Object entry; entry.push_back(Pair("account", acentry.strAccount)); entry.push_back(Pair("category", "move")); - entry.push_back(Pair("time", (boost::int64_t)acentry.nTime)); + entry.push_back(Pair("time", acentry.nTime)); entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit))); entry.push_back(Pair("otheraccount", acentry.strOtherAccount)); entry.push_back(Pair("comment", acentry.strComment)); @@ -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); @@ -1747,7 +1824,7 @@ Value lockunspent(const Array& params, bool fHelp) throw runtime_error( "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n" "\nUpdates list of temporarily unspendable outputs.\n" - "Temporarily lock (lock=true) or unlock (lock=false) specified transaction outputs.\n" + "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n" "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n" "is always cleared (by virtue of process exit) when a node stops or fails.\n" @@ -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; } @@ -1912,9 +1989,9 @@ Value getwalletinfo(const Array& params, bool fHelp) obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size())); - obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); + obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); if (pwalletMain->IsCrypted()) - obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime)); + obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); return obj; } diff --git a/src/script.cpp b/src/script.cpp index 810ba16d28..238a25e72d 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -5,11 +5,13 @@ #include "script.h" -#include "bignum.h" #include "core.h" #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" @@ -25,22 +27,13 @@ typedef vector<unsigned char> valtype; static const valtype vchFalse(0); static const valtype vchZero(0); static const valtype vchTrue(1, 1); -static const CBigNum bnZero(0); -static const CBigNum bnOne(1); -static const CBigNum bnFalse(0); -static const CBigNum bnTrue(1); -static const size_t nMaxNumSize = 4; +static const CScriptNum bnZero(0); +static const CScriptNum bnOne(1); +static const CScriptNum bnFalse(0); +static const CScriptNum bnTrue(1); bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); -CBigNum CastToBigNum(const valtype& vch) -{ - if (vch.size() > nMaxNumSize) - throw runtime_error("CastToBigNum() : overflow"); - // Get rid of extra leading zeros - return CBigNum(CBigNum(vch).getvch()); -} - bool CastToBool(const valtype& vch) { for (unsigned int i = 0; i < vch.size(); i++) @@ -218,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"; } @@ -296,9 +288,12 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) return error("Non-canonical signature: S value excessively padded"); - if (flags & SCRIPT_VERIFY_EVEN_S) { - if (S[nLenS-1] & 1) - return error("Non-canonical signature: S value odd"); + if (flags & SCRIPT_VERIFY_LOW_S) { + // If the S value is above the order of the curve divided by two, its + // complement modulo the order could have been used instead, which is + // one byte shorter when encoded correctly. + if (!CKey::CheckSignatureElement(S, nLenS, true)) + return error("Non-canonical signature: S value is unnecessarily high"); } return true; @@ -306,7 +301,6 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { - CAutoBN_CTX pctx; CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); CScript::const_iterator pbegincodehash = script.begin(); @@ -380,7 +374,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co case OP_16: { // ( -- value) - CBigNum bn((int)opcode - (int)(OP_1 - 1)); + CScriptNum bn((int)opcode - (int)(OP_1 - 1)); stack.push_back(bn.getvch()); } break; @@ -556,7 +550,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co case OP_DEPTH: { // -- stacksize - CBigNum bn(stack.size()); + CScriptNum bn(stack.size()); stack.push_back(bn.getvch()); } break; @@ -606,7 +600,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) if (stack.size() < 2) return false; - int n = CastToBigNum(stacktop(-1)).getint(); + int n = CScriptNum(stacktop(-1)).getint(); popstack(stack); if (n < 0 || n >= (int)stack.size()) return false; @@ -654,7 +648,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // (in -- in size) if (stack.size() < 1) return false; - CBigNum bn(stacktop(-1).size()); + CScriptNum bn(stacktop(-1).size()); stack.push_back(bn.getvch()); } break; @@ -705,7 +699,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // (in -- out) if (stack.size() < 1) return false; - CBigNum bn = CastToBigNum(stacktop(-1)); + CScriptNum bn(stacktop(-1)); switch (opcode) { case OP_1ADD: bn += bnOne; break; @@ -738,9 +732,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // (x1 x2 -- out) if (stack.size() < 2) return false; - CBigNum bn1 = CastToBigNum(stacktop(-2)); - CBigNum bn2 = CastToBigNum(stacktop(-1)); - CBigNum bn; + CScriptNum bn1(stacktop(-2)); + CScriptNum bn2(stacktop(-1)); + CScriptNum bn(0); switch (opcode) { case OP_ADD: @@ -783,9 +777,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // (x min max -- out) if (stack.size() < 3) return false; - CBigNum bn1 = CastToBigNum(stacktop(-3)); - CBigNum bn2 = CastToBigNum(stacktop(-2)); - CBigNum bn3 = CastToBigNum(stacktop(-1)); + CScriptNum bn1(stacktop(-3)); + CScriptNum bn2(stacktop(-2)); + CScriptNum bn3(stacktop(-1)); bool fValue = (bn2 <= bn1 && bn1 < bn3); popstack(stack); popstack(stack); @@ -810,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); } @@ -847,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); @@ -882,7 +866,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co if ((int)stack.size() < i) return false; - int nKeysCount = CastToBigNum(stacktop(-i)).getint(); + int nKeysCount = CScriptNum(stacktop(-i)).getint(); if (nKeysCount < 0 || nKeysCount > 20) return false; nOpCount += nKeysCount; @@ -893,7 +877,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co if ((int)stack.size() < i) return false; - int nSigsCount = CastToBigNum(stacktop(-i)).getint(); + int nSigsCount = CScriptNum(stacktop(-i)).getint(); if (nSigsCount < 0 || nSigsCount > nKeysCount) return false; int isig = ++i; @@ -934,8 +918,22 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co fSuccess = false; } - while (i-- > 0) + // Clean up stack of actual arguments + while (i-- > 1) popstack(stack); + + // A bug causes CHECKMULTISIG to consume one extra argument + // whose contents were not checked in any way. + // + // Unfortunately this is a potential source of mutability, + // so optionally verify it is exactly equal to zero prior + // to removing it from the stack. + if (stack.size() < 1) + return false; + if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size()) + return error("CHECKMULTISIG dummy argument not null"); + popstack(stack); + stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKMULTISIGVERIFY) @@ -976,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 */ @@ -1068,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) { @@ -1094,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) @@ -1210,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)); } @@ -1456,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: { @@ -1495,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) @@ -1638,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]; @@ -1670,10 +1688,10 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa } // Test solution - return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0); + 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]; @@ -1691,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 657ac0b388..e36be2db9e 100644 --- a/src/script.h +++ b/src/script.h @@ -6,7 +6,6 @@ #ifndef H_BITCOIN_SCRIPT #define H_BITCOIN_SCRIPT -#include "bignum.h" #include "key.h" #include "util.h" @@ -21,10 +20,160 @@ 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 +class scriptnum_error : public std::runtime_error +{ +public: + explicit scriptnum_error(const std::string& str) : std::runtime_error(str) {} +}; + +class CScriptNum +{ +// Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers. +// The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1], +// but results may overflow (and are valid as long as they are not used in a subsequent +// numeric operation). CScriptNum enforces those semantics by storing results as +// an int64 and allowing out-of-range values to be returned as a vector of bytes but +// throwing an exception if arithmetic is done or the result is interpreted as an integer. +public: + + explicit CScriptNum(const int64_t& n) + { + m_value = n; + } + + explicit CScriptNum(const std::vector<unsigned char>& vch) + { + if (vch.size() > nMaxNumSize) + throw scriptnum_error("CScriptNum(const std::vector<unsigned char>&) : overflow"); + m_value = set_vch(vch); + } + + inline bool operator==(const int64_t& rhs) const { return m_value == rhs; } + inline bool operator!=(const int64_t& rhs) const { return m_value != rhs; } + inline bool operator<=(const int64_t& rhs) const { return m_value <= rhs; } + inline bool operator< (const int64_t& rhs) const { return m_value < rhs; } + inline bool operator>=(const int64_t& rhs) const { return m_value >= rhs; } + inline bool operator> (const int64_t& rhs) const { return m_value > rhs; } + + inline bool operator==(const CScriptNum& rhs) const { return operator==(rhs.m_value); } + inline bool operator!=(const CScriptNum& rhs) const { return operator!=(rhs.m_value); } + inline bool operator<=(const CScriptNum& rhs) const { return operator<=(rhs.m_value); } + inline bool operator< (const CScriptNum& rhs) const { return operator< (rhs.m_value); } + inline bool operator>=(const CScriptNum& rhs) const { return operator>=(rhs.m_value); } + inline bool operator> (const CScriptNum& rhs) const { return operator> (rhs.m_value); } + + inline CScriptNum operator+( const int64_t& rhs) const { return CScriptNum(m_value + rhs);} + inline CScriptNum operator-( const int64_t& rhs) const { return CScriptNum(m_value - rhs);} + inline CScriptNum operator+( const CScriptNum& rhs) const { return operator+(rhs.m_value); } + inline CScriptNum operator-( const CScriptNum& rhs) const { return operator-(rhs.m_value); } + + inline CScriptNum& operator+=( const CScriptNum& rhs) { return operator+=(rhs.m_value); } + inline CScriptNum& operator-=( const CScriptNum& rhs) { return operator-=(rhs.m_value); } + + inline CScriptNum operator-() const + { + assert(m_value != std::numeric_limits<int64_t>::min()); + return CScriptNum(-m_value); + } + + inline CScriptNum& operator=( const int64_t& rhs) + { + m_value = rhs; + return *this; + } + + inline CScriptNum& operator+=( const int64_t& rhs) + { + assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || + (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)); + m_value += rhs; + return *this; + } + + inline CScriptNum& operator-=( const int64_t& rhs) + { + assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || + (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)); + m_value -= rhs; + return *this; + } + + int getint() const + { + if (m_value > std::numeric_limits<int>::max()) + return std::numeric_limits<int>::max(); + else if (m_value < std::numeric_limits<int>::min()) + return std::numeric_limits<int>::min(); + return m_value; + } + + std::vector<unsigned char> getvch() const + { + return serialize(m_value); + } + + static std::vector<unsigned char> serialize(const int64_t& value) + { + if(value == 0) + return std::vector<unsigned char>(); + + std::vector<unsigned char> result; + const bool neg = value < 0; + uint64_t absvalue = neg ? -value : value; + + while(absvalue) + { + result.push_back(absvalue & 0xff); + absvalue >>= 8; + } + + +// - If the most significant byte is >= 0x80 and the value is positive, push a +// new zero-byte to make the significant byte < 0x80 again. + +// - If the most significant byte is >= 0x80 and the value is negative, push a +// new 0x80 byte that will be popped off when converting to an integral. + +// - If the most significant byte is < 0x80 and the value is negative, add +// 0x80 to it, since it will be subtracted and interpreted as a negative when +// converting to an integral. + + if (result.back() & 0x80) + result.push_back(neg ? 0x80 : 0); + else if (neg) + result.back() |= 0x80; + + return result; + } + + static const size_t nMaxNumSize = 4; + +private: + static int64_t set_vch(const std::vector<unsigned char>& vch) + { + if (vch.empty()) + return 0; + + int64_t result = 0; + for (size_t i = 0; i != vch.size(); ++i) + result |= static_cast<int64_t>(vch[i]) << 8*i; + + // If the input vector's most significant byte is 0x80, remove it from + // the result's msb and return a negative. + if (vch.back() & 0x80) + return -(result & ~(0x80 << (8 * (vch.size() - 1)))); + + return result; + } + + int64_t m_value; +}; + /** Signature hash types/flags */ enum { @@ -40,10 +189,41 @@ enum SCRIPT_VERIFY_NONE = 0, SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys - SCRIPT_VERIFY_EVEN_S = (1U << 2), // enforce even S values in signatures (depends on STRICTENC) + SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC) SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it) + 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 +// strict DER encoding. +// +// Failing one of these tests may trigger a DoS ban - see CheckInputs() for +// details. +static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH; + +// Standard script verification flags that standard transactions will comply +// with. However scripts violating these flags may still be present in valid +// blocks and we must accept those blocks. +static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS | + SCRIPT_VERIFY_STRICTENC | + SCRIPT_VERIFY_NULLDUMMY; + +// For convenience, standard but not mandatory verify flags. +static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; + enum txnouttype { TX_NONSTANDARD, @@ -225,7 +405,7 @@ const char* GetOpName(opcodetype opcode); inline std::string ValueString(const std::vector<unsigned char>& vch) { if (vch.size() <= 4) - return strprintf("%d", CBigNum(vch).getint()); + return strprintf("%d", CScriptNum(vch).getint()); else return HexStr(vch); } @@ -261,26 +441,10 @@ protected: } else { - CBigNum bn(n); - *this << bn.getvch(); + *this << CScriptNum::serialize(n); } return *this; } - - CScript& push_uint64(uint64_t n) - { - if (n >= 1 && n <= 16) - { - push_back(n + (OP_1 - 1)); - } - else - { - CBigNum bn(n); - *this << bn.getvch(); - } - return *this; - } - public: CScript() { } CScript(const CScript& b) : std::vector<unsigned char>(b.begin(), b.end()) { } @@ -303,35 +467,15 @@ public: } - //explicit CScript(char b) is not portable. Use 'signed char' or 'unsigned char'. - explicit CScript(signed char b) { operator<<(b); } - explicit CScript(short b) { operator<<(b); } - explicit CScript(int b) { operator<<(b); } - explicit CScript(long b) { operator<<(b); } - explicit CScript(long long b) { operator<<(b); } - explicit CScript(unsigned char b) { operator<<(b); } - explicit CScript(unsigned int b) { operator<<(b); } - explicit CScript(unsigned short b) { operator<<(b); } - explicit CScript(unsigned long b) { operator<<(b); } - explicit CScript(unsigned long long b) { operator<<(b); } + CScript(int64_t b) { operator<<(b); } explicit CScript(opcodetype b) { operator<<(b); } explicit CScript(const uint256& b) { operator<<(b); } - explicit CScript(const CBigNum& b) { operator<<(b); } + explicit CScript(const CScriptNum& b) { operator<<(b); } explicit CScript(const std::vector<unsigned char>& b) { operator<<(b); } - //CScript& operator<<(char b) is not portable. Use 'signed char' or 'unsigned char'. - CScript& operator<<(signed char b) { return push_int64(b); } - CScript& operator<<(short b) { return push_int64(b); } - CScript& operator<<(int b) { return push_int64(b); } - CScript& operator<<(long b) { return push_int64(b); } - CScript& operator<<(long long b) { return push_int64(b); } - CScript& operator<<(unsigned char b) { return push_uint64(b); } - CScript& operator<<(unsigned int b) { return push_uint64(b); } - CScript& operator<<(unsigned short b) { return push_uint64(b); } - CScript& operator<<(unsigned long b) { return push_uint64(b); } - CScript& operator<<(unsigned long long b) { return push_uint64(b); } + CScript& operator<<(int64_t b) { return push_int64(b); } CScript& operator<<(opcodetype opcode) { @@ -363,7 +507,7 @@ public: return *this; } - CScript& operator<<(const CBigNum& b) + CScript& operator<<(const CScriptNum& b) { *this << b.getvch(); return *this; @@ -559,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; @@ -588,11 +726,6 @@ public: return str; } - void print() const - { - LogPrintf("%s\n", ToString().c_str()); - } - CScriptID GetID() const { return CScriptID(Hash160(*this)); @@ -648,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> @@ -662,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)); } }; @@ -679,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 d86cc7a290..5e17555e7a 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -8,10 +8,10 @@ -#include "bignum.h" #include "keystore.h" #include "main.h" #include "net.h" +#include "pow.h" #include "script.h" #include "serialize.h" @@ -106,9 +106,9 @@ static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2, return CheckNBits(nbits2, time2, nbits1, time1); int64_t deltaTime = time2-time1; - CBigNum required; + uint256 required; required.SetCompact(ComputeMinWork(nbits1, deltaTime)); - CBigNum have; + uint256 have; have.SetCompact(nbits2); return (have <= required); } @@ -168,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(); @@ -185,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(); @@ -202,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()); @@ -231,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 b375ba1306..0000000000 --- a/src/test/Makefile.am +++ /dev/null @@ -1,76 +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 = \ - alert_tests.cpp \ - allocator_tests.cpp \ - base32_tests.cpp \ - base58_tests.cpp \ - base64_tests.cpp \ - bignum_tests.cpp \ - bloom_tests.cpp \ - canonical_tests.cpp \ - checkblock_tests.cpp \ - Checkpoints_tests.cpp \ - compress_tests.cpp \ - DoS_tests.cpp \ - getarg_tests.cpp \ - key_tests.cpp \ - 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 \ - 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 5689e69995..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(); @@ -233,7 +233,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) continue; } CBitcoinAddress addrOut; - BOOST_CHECK_MESSAGE(boost::apply_visitor(CBitcoinAddressVisitor(&addrOut), dest), "encode dest: " + strTest); + BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest); BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest); } } @@ -241,9 +241,9 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) // Visiting a CNoDestination must fail CBitcoinAddress dummyAddr; CTxDestination nodest = CNoDestination(); - BOOST_CHECK(!boost::apply_visitor(CBitcoinAddressVisitor(&dummyAddr), nodest)); + 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/bignum.h b/src/test/bignum.h new file mode 100644 index 0000000000..a75f5250fa --- /dev/null +++ b/src/test/bignum.h @@ -0,0 +1,180 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2013 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_BIGNUM_H +#define BITCOIN_BIGNUM_H + +#include <algorithm> +#include <limits> +#include <stdexcept> +#include <stdint.h> +#include <string> +#include <vector> + +#include <openssl/bn.h> + +class bignum_error : public std::runtime_error +{ +public: + explicit bignum_error(const std::string& str) : std::runtime_error(str) {} +}; + + +/** C++ wrapper for BIGNUM (OpenSSL bignum) */ +class CBigNum : public BIGNUM +{ +public: + CBigNum() + { + BN_init(this); + } + + CBigNum(const CBigNum& b) + { + BN_init(this); + if (!BN_copy(this, &b)) + { + BN_clear_free(this); + throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); + } + } + + CBigNum& operator=(const CBigNum& b) + { + if (!BN_copy(this, &b)) + throw bignum_error("CBigNum::operator= : BN_copy failed"); + return (*this); + } + + ~CBigNum() + { + BN_clear_free(this); + } + + CBigNum(long long n) { BN_init(this); setint64(n); } + + explicit CBigNum(const std::vector<unsigned char>& vch) + { + BN_init(this); + setvch(vch); + } + + int getint() const + { + unsigned long n = BN_get_word(this); + if (!BN_is_negative(this)) + return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n); + else + return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n); + } + + void setint64(int64_t sn) + { + unsigned char pch[sizeof(sn) + 6]; + unsigned char* p = pch + 4; + bool fNegative; + uint64_t n; + + if (sn < (int64_t)0) + { + // Since the minimum signed integer cannot be represented as positive so long as its type is signed, + // and it's not well-defined what happens if you make it unsigned before negating it, + // we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate + n = -(sn + 1); + ++n; + fNegative = true; + } else { + n = sn; + fNegative = false; + } + + bool fLeadingZeroes = true; + for (int i = 0; i < 8; i++) + { + unsigned char c = (n >> 56) & 0xff; + n <<= 8; + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = (fNegative ? 0x80 : 0); + else if (fNegative) + c |= 0x80; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize) & 0xff; + BN_mpi2bn(pch, p - pch, this); + } + + void setvch(const std::vector<unsigned char>& vch) + { + std::vector<unsigned char> vch2(vch.size() + 4); + unsigned int nSize = vch.size(); + // BIGNUM's byte stream format expects 4 bytes of + // big endian size data info at the front + vch2[0] = (nSize >> 24) & 0xff; + vch2[1] = (nSize >> 16) & 0xff; + vch2[2] = (nSize >> 8) & 0xff; + vch2[3] = (nSize >> 0) & 0xff; + // swap data to big endian + reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); + BN_mpi2bn(&vch2[0], vch2.size(), this); + } + + std::vector<unsigned char> getvch() const + { + unsigned int nSize = BN_bn2mpi(this, NULL); + if (nSize <= 4) + return std::vector<unsigned char>(); + std::vector<unsigned char> vch(nSize); + BN_bn2mpi(this, &vch[0]); + vch.erase(vch.begin(), vch.begin() + 4); + reverse(vch.begin(), vch.end()); + return vch; + } + + friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); +}; + + + +inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) +{ + CBigNum r; + if (!BN_add(&r, &a, &b)) + throw bignum_error("CBigNum::operator+ : BN_add failed"); + return r; +} + +inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) +{ + CBigNum r; + if (!BN_sub(&r, &a, &b)) + throw bignum_error("CBigNum::operator- : BN_sub failed"); + return r; +} + +inline const CBigNum operator-(const CBigNum& a) +{ + CBigNum r(a); + BN_set_negative(&r, !BN_is_negative(&r)); + return r; +} + +inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); } +inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); } +inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); } +inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); } +inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); } +inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); } + +#endif diff --git a/src/test/bignum_tests.cpp b/src/test/bignum_tests.cpp deleted file mode 100644 index d5ee8c9778..0000000000 --- a/src/test/bignum_tests.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) 2012-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 "bignum.h" - -#include <limits> -#include <stdint.h> - -#include <boost/test/unit_test.hpp> - -BOOST_AUTO_TEST_SUITE(bignum_tests) - -// Unfortunately there's no standard way of preventing a function from being -// inlined, so we define a macro for it. -// -// You should use it like this: -// NOINLINE void function() {...} -#if defined(__GNUC__) -// This also works and will be defined for any compiler implementing GCC -// extensions, such as Clang and ICC. -#define NOINLINE __attribute__((noinline)) -#elif defined(_MSC_VER) -#define NOINLINE __declspec(noinline) -#else -// We give out a warning because it impacts the correctness of one bignum test. -#warning You should define NOINLINE for your compiler. -#define NOINLINE -#endif - -// For the following test case, it is useful to use additional tools. -// -// The simplest one to use is the compiler flag -ftrapv, which detects integer -// overflows and similar errors. However, due to optimizations and compilers -// taking advantage of undefined behavior sometimes it may not actually detect -// anything. -// -// You can also use compiler-based stack protection to possibly detect possible -// stack buffer overruns. -// -// For more accurate diagnostics, you can use an undefined arithmetic operation -// detector such as the clang's undefined behaviour checker. -// See also: http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation -// -// It might also be useful to use Google's AddressSanitizer to detect -// stack buffer overruns, which valgrind can't currently detect. - -// Let's force this code not to be inlined, in order to actually -// test a generic version of the function. This increases the chance -// that -ftrapv will detect overflows. -NOINLINE void mysetint64(CBigNum& num, int64_t n) -{ - num.setint64(n); -} - -// For each number, we do 2 tests: one with inline code, then we reset the -// value to 0, then the second one with a non-inlined function. -BOOST_AUTO_TEST_CASE(bignum_setint64) -{ - int64_t n; - - { - n = 0; - CBigNum num(n); - BOOST_CHECK(num.ToString() == "0"); - num.setulong(0); - BOOST_CHECK(num.ToString() == "0"); - mysetint64(num, n); - BOOST_CHECK(num.ToString() == "0"); - } - { - n = 1; - CBigNum num(n); - BOOST_CHECK(num.ToString() == "1"); - num.setulong(0); - BOOST_CHECK(num.ToString() == "0"); - mysetint64(num, n); - BOOST_CHECK(num.ToString() == "1"); - } - { - n = -1; - CBigNum num(n); - BOOST_CHECK(num.ToString() == "-1"); - num.setulong(0); - BOOST_CHECK(num.ToString() == "0"); - mysetint64(num, n); - BOOST_CHECK(num.ToString() == "-1"); - } - { - n = 5; - CBigNum num(n); - BOOST_CHECK(num.ToString() == "5"); - num.setulong(0); - BOOST_CHECK(num.ToString() == "0"); - mysetint64(num, n); - BOOST_CHECK(num.ToString() == "5"); - } - { - n = -5; - CBigNum num(n); - BOOST_CHECK(num.ToString() == "-5"); - num.setulong(0); - BOOST_CHECK(num.ToString() == "0"); - mysetint64(num, n); - BOOST_CHECK(num.ToString() == "-5"); - } - { - n = std::numeric_limits<int64_t>::min(); - CBigNum num(n); - BOOST_CHECK(num.ToString() == "-9223372036854775808"); - num.setulong(0); - BOOST_CHECK(num.ToString() == "0"); - mysetint64(num, n); - BOOST_CHECK(num.ToString() == "-9223372036854775808"); - } - { - n = std::numeric_limits<int64_t>::max(); - CBigNum num(n); - BOOST_CHECK(num.ToString() == "9223372036854775807"); - num.setulong(0); - BOOST_CHECK(num.ToString() == "0"); - mysetint64(num, n); - BOOST_CHECK(num.ToString() == "9223372036854775807"); - } -} - - -BOOST_AUTO_TEST_CASE(bignum_SetCompact) -{ - CBigNum num; - num.SetCompact(0); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x00123456); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x01003456); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x02000056); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x03000000); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x04000000); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x00923456); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x01803456); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x02800056); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x03800000); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x04800000); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x01123456); - BOOST_CHECK_EQUAL(num.GetHex(), "12"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000U); - - // Make sure that we don't generate compacts with the 0x00800000 bit set - num = 0x80; - BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000U); - - num.SetCompact(0x01fedcba); - BOOST_CHECK_EQUAL(num.GetHex(), "-7e"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x01fe0000U); - - num.SetCompact(0x02123456); - BOOST_CHECK_EQUAL(num.GetHex(), "1234"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400U); - - num.SetCompact(0x03123456); - BOOST_CHECK_EQUAL(num.GetHex(), "123456"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456U); - - num.SetCompact(0x04123456); - BOOST_CHECK_EQUAL(num.GetHex(), "12345600"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456U); - - num.SetCompact(0x04923456); - BOOST_CHECK_EQUAL(num.GetHex(), "-12345600"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x04923456U); - - num.SetCompact(0x05009234); - BOOST_CHECK_EQUAL(num.GetHex(), "92340000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234U); - - num.SetCompact(0x20123456); - BOOST_CHECK_EQUAL(num.GetHex(), "1234560000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456U); - - num.SetCompact(0xff123456); - BOOST_CHECK_EQUAL(num.GetHex(), "123456000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0xff123456U); -} - -BOOST_AUTO_TEST_CASE(bignum_SetHex) -{ - std::string hexStr = "deecf97fd890808b9cc0f1b6a3e7a60b400f52710e6ad075b1340755bfa58cc9"; - CBigNum num; - num.SetHex(hexStr); - BOOST_CHECK_EQUAL(num.GetHex(), hexStr); -} - -BOOST_AUTO_TEST_SUITE_END() 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/canonical_tests.cpp b/src/test/canonical_tests.cpp index a26ad335a4..23dd74296c 100644 --- a/src/test/canonical_tests.cpp +++ b/src/test/canonical_tests.cpp @@ -93,4 +93,21 @@ BOOST_AUTO_TEST_CASE(script_noncanon) } } +BOOST_AUTO_TEST_CASE(script_signstrict) +{ + for (int i=0; i<100; i++) { + CKey key; + key.MakeNewKey(i & 1); + std::vector<unsigned char> sig; + uint256 hash = GetRandHash(); + + BOOST_CHECK(key.Sign(hash, sig)); // Generate a random signature. + BOOST_CHECK(key.GetPubKey().Verify(hash, sig)); // Check it. + sig.push_back(0x01); // Append a sighash type. + + BOOST_CHECK(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_LOW_S)); + BOOST_CHECK(IsCanonicalSignature_OpenSSL(sig)); + } +} + BOOST_AUTO_TEST_SUITE_END() 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/script_invalid.json b/src/test/data/script_invalid.json index 8cb365a46f..d623e974b8 100644 --- a/src/test/data/script_invalid.json +++ b/src/test/data/script_invalid.json @@ -1,8 +1,18 @@ [ +["", "DEPTH", "Test the test: we should have an empty stack after scriptSig evaluation"], +[" ", "DEPTH", "and multiple spaces should not change that."], +[" ", "DEPTH"], +[" ", "DEPTH"], + ["", ""], ["", "NOP"], +["", "NOP DEPTH"], ["NOP", ""], +["NOP", "DEPTH"], ["NOP","NOP"], +["NOP","NOP DEPTH"], + +["DEPTH", ""], ["0x4c01","0x01 NOP", "PUSHDATA1 with not enough bytes"], ["0x4d0200ff","0x01 NOP", "PUSHDATA2 with not enough bytes"], @@ -257,7 +267,10 @@ ["1","0xba", "0xba == OP_NOP10 + 1"], ["2147483648", "1ADD 1", "We cannot do math on 5-byte integers"], +["2147483648", "NEGATE 1", "We cannot do math on 5-byte integers"], ["-2147483648", "1ADD 1", "Because we use a sign bit, -2147483648 is also 5 bytes"], +["2147483647", "1ADD 1SUB 1", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], +["2147483648", "1SUB 1", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], ["1", "1 ENDIF", "ENDIF without IF"], ["1", "IF 1", "IF without ENDIF"], @@ -321,6 +334,22 @@ ["NOP", "HASH160 1"], ["NOP", "HASH256 1"], +["", +"0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG", +"202 CHECKMULTISIGS, fails due to 201 op limit"], + +["1", +"0 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY"], + +["", +"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG", +"Fails due to 201 sig op limit"], + +["1", +"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY"], + + + ["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "Tests for Script.IsPushOnly()"], ["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL"], diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json index 3b4c191865..7546a3b1fe 100644 --- a/src/test/data/script_valid.json +++ b/src/test/data/script_valid.json @@ -1,4 +1,16 @@ [ +["", "DEPTH 0 EQUAL", "Test the test: we should have an empty stack after scriptSig evaluation"], +[" ", "DEPTH 0 EQUAL", "and multiple spaces should not change that."], +[" ", "DEPTH 0 EQUAL"], +[" ", "DEPTH 0 EQUAL"], +["1 2", "2 EQUALVERIFY 1 EQUAL", "Similarly whitespace around and between symbols"], +["1 2", "2 EQUALVERIFY 1 EQUAL"], +[" 1 2", "2 EQUALVERIFY 1 EQUAL"], +["1 2 ", "2 EQUALVERIFY 1 EQUAL"], +[" 1 2 ", "2 EQUALVERIFY 1 EQUAL"], + +["1", ""], + ["0x01 0x0b", "11 EQUAL", "push 1 byte"], ["0x02 0x417a", "'Az' EQUAL"], ["0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a", @@ -97,6 +109,9 @@ ["8388608", "SIZE 4 EQUAL"], ["2147483647", "SIZE 4 EQUAL"], ["2147483648", "SIZE 5 EQUAL"], +["549755813887", "SIZE 5 EQUAL"], +["549755813888", "SIZE 6 EQUAL"], +["9223372036854775807", "SIZE 8 EQUAL"], ["-1", "SIZE 1 EQUAL"], ["-127", "SIZE 1 EQUAL"], ["-128", "SIZE 2 EQUAL"], @@ -106,6 +121,9 @@ ["-8388608", "SIZE 4 EQUAL"], ["-2147483647", "SIZE 4 EQUAL"], ["-2147483648", "SIZE 5 EQUAL"], +["-549755813887", "SIZE 5 EQUAL"], +["-549755813888", "SIZE 6 EQUAL"], +["-9223372036854775807", "SIZE 8 EQUAL"], ["'abcdefghijklmnopqrstuvwxyz'", "SIZE 26 EQUAL"], @@ -306,6 +324,9 @@ ["8388608", "0x04 0x00008000 EQUAL"], ["2147483647", "0x04 0xFFFFFF7F EQUAL"], ["2147483648", "0x05 0x0000008000 EQUAL"], +["549755813887", "0x05 0xFFFFFFFF7F EQUAL"], +["549755813888", "0x06 0xFFFFFFFF7F EQUAL"], +["9223372036854775807", "0x08 0xFFFFFFFFFFFFFF7F EQUAL"], ["-1", "0x01 0x81 EQUAL", "Numbers are little-endian with the MSB being a sign bit"], ["-127", "0x01 0xFF EQUAL"], ["-128", "0x02 0x8080 EQUAL"], @@ -315,6 +336,10 @@ ["-8388608", "0x04 0x00008080 EQUAL"], ["-2147483647", "0x04 0xFFFFFFFF EQUAL"], ["-2147483648", "0x05 0x0000008080 EQUAL"], +["-4294967295", "0x05 0xFFFFFFFF80 EQUAL"], +["-549755813887", "0x05 0xFFFFFFFFFF EQUAL"], +["-549755813888", "0x06 0x000000008080 EQUAL"], +["-9223372036854775807", "0x08 0xFFFFFFFFFFFFFFFF EQUAL"], ["2147483647", "1ADD 2147483648 EQUAL", "We can do math on 4-byte integers, and compare 5-byte ones"], ["2147483647", "1ADD 1"], @@ -402,6 +427,70 @@ ["NOP", "NOP9 1"], ["NOP", "NOP10 1"], +["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "CHECKMULTISIG is allowed to have zero keys and/or sigs"], +["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "Zero sigs means no sigs are checked"], +["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], + +["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "CHECKMULTISIG is allowed to have zero keys and/or sigs"], +["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "Zero sigs means no sigs are checked"], +["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], + +["", "0 0 'a' 'b' 2 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "Test from up to 20 pubkeys, all not checked"], +["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG VERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 2 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY DEPTH 0 EQUAL"], + +["", +"0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG", +"nOpCount is incremented by the number of keys evaluated in addition to the usual one op per op. In this case we have zero keys, so we can execute 201 CHECKMULTISIGS"], + +["1", +"0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY"], + +["", +"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG", +"Even though there are no signatures being checked nOpCount is incremented by the number of keys."], + +["1", +"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY"], + ["0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "Very basic P2SH"], ["0x4c 0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL"], diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index faf40ef23d..638a705f9f 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -2,79 +2,106 @@ ["The following are deserialized transactions which are invalid."], ["They are in the form"], ["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], -["serializedTransaction, enforceP2SH]"], +["serializedTransaction, verifyFlags]"], ["Objects that are only a single string (like this one) are ignored"], ["0e1b5688cf179cd9f7cbda1fac0090f6e684bbf8cd946660120197c3f3681809 but with extra junk appended to the end of the scriptPubKey"], [[["6ca7ec7b1847f6bdbd737176050e6a08d66ccd55bb94ad24f4018024107a5827", 0, "0x41 0x043b640e983c9690a14c039a2037ecc3467b27a0dcd58f19d76c7bc118d09fec45adc5370a1c5bf8067ca9f5557a4cf885fdb0fe0dcc9c3a7137226106fbc779a5 CHECKSIG VERIFY 1"]], -"010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000", true], +"010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000", "P2SH"], ["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json"], ["but with the signature duplicated in the scriptPubKey with a non-standard pushdata prefix"], ["See FindAndDelete, which will only remove if it uses the same pushdata prefix as is standard"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], ["Same as above, but with the sig in the scriptSig also pushed with the same non-standard OP_PUSHDATA"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], ["An invalid P2SH Transaction"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], -"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", true], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "P2SH"], ["Tests for CheckTransaction()"], ["No inputs"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], -"0100000000010000000000000000015100000000", true], +"0100000000010000000000000000015100000000", "P2SH"], ["No outputs"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x05ab9e14d983742513f0f451e105ffb4198d1dd4 EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e03dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b571e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f0651c7acffffffff0000000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e03dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b571e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f0651c7acffffffff0000000000", "P2SH"], ["Negative output"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xae609aca8061d77c5e111f6bb62501a6bbe2bfdb EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d4830450220063222cbb128731fc09de0d7323746539166544d6c1df84d867ccea84bcc8903022100bf568e8552844de664cd41648a031554327aa8844af34b4f27397c65b92c04de0123210243ec37dee0e2e053a9c976f43147e79bc7d9dc606ea51010af1ac80db6b069e1acffffffff01ffffffffffffffff015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d4830450220063222cbb128731fc09de0d7323746539166544d6c1df84d867ccea84bcc8903022100bf568e8552844de664cd41648a031554327aa8844af34b4f27397c65b92c04de0123210243ec37dee0e2e053a9c976f43147e79bc7d9dc606ea51010af1ac80db6b069e1acffffffff01ffffffffffffffff015100000000", "P2SH"], ["MAX_MONEY + 1 output"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010140075af0750700015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010140075af0750700015100000000", "P2SH"], ["MAX_MONEY output + 1 output"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510001000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510001000000000000015100000000", "P2SH"], ["Duplicate inputs"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x236d0639db62b0773fd8ac34dc85ae19e9aba80a EQUAL"]], -"01000000020001000000000000000000000000000000000000000000000000000000000000000000006c47304402204bb1197053d0d7799bf1b30cd503c44b58d6240cccbdc85b6fe76d087980208f02204beeed78200178ffc6c74237bb74b3f276bbb4098b5605d814304fe128bf1431012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff0001000000000000000000000000000000000000000000000000000000000000000000006c47304402202306489afef52a6f62e90bf750bbcdf40c06f5c6b138286e6b6b86176bb9341802200dba98486ea68380f47ebb19a7df173b99e6bc9c681d6ccf3bde31465d1f16b3012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff010000000000000000015100000000", true], +"01000000020001000000000000000000000000000000000000000000000000000000000000000000006c47304402204bb1197053d0d7799bf1b30cd503c44b58d6240cccbdc85b6fe76d087980208f02204beeed78200178ffc6c74237bb74b3f276bbb4098b5605d814304fe128bf1431012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff0001000000000000000000000000000000000000000000000000000000000000000000006c47304402202306489afef52a6f62e90bf750bbcdf40c06f5c6b138286e6b6b86176bb9341802200dba98486ea68380f47ebb19a7df173b99e6bc9c681d6ccf3bde31465d1f16b3012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff010000000000000000015100000000", "P2SH"], ["Coinbase of size 1"], ["Note the input is just required to make the tester happy"], [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff010000000000000000015100000000", true], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff010000000000000000015100000000", "P2SH"], ["Coinbase of size 101"], ["Note the input is just required to make the tester happy"], [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"], ["Null txin"], [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "HASH160 0x14 0x02dae7dbbda56097959cba59b1989dd3e47937bf EQUAL"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", true], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", "P2SH"], ["Same as the transactions in valid with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], - "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", true], + "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", "P2SH"], -["Incorrect signature order"], +["CHECKMULTISIG with incorrect signature order"], ["Note the input is just required to make the tester happy"], [[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]], -"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe000048304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f401483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", true], +"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe000048304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f401483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "P2SH"], + + +["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], +["It is an OP_CHECKMULTISIG with the dummy value missing"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004847304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], + + +["CHECKMULTISIG SCRIPT_VERIFY_NULLDUMMY tests:"], + +["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"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a010047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], + +["As above, but using a OP_1"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], + +["As above, but using a OP_1NEGATE"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], + +["As above, but with the dummy byte missing"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004847304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], + ["Empty stack when we try to run CHECKSIG"], [[["ad503f72c18df5801ee64d76090afe4c607fb2b822e9b7b63c5826c50e22fc3b", 0, "0x21 0x027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5 CHECKSIG NOT"]], -"01000000013bfc220ec526583cb6b7e922b8b27f604cfe0a09764de61e80f58dc1723f50ad0000000000ffffffff0101000000000000002321027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5ac00000000", true], +"01000000013bfc220ec526583cb6b7e922b8b27f604cfe0a09764de61e80f58dc1723f50ad0000000000ffffffff0101000000000000002321027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5ac00000000", "P2SH"], ["Make diffs cleaner by leaving a comment here without comma at the end"] ] diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json index c206f7a722..aa8e5ca6c3 100644 --- a/src/test/data/tx_valid.json +++ b/src/test/data/tx_valid.json @@ -2,7 +2,7 @@ ["The following are deserialized transactions which are valid."], ["They are in the form"], ["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], -["serializedTransaction, enforceP2SH]"], +["serializedTransaction, verifyFlags]"], ["Objects that are only a single string (like this one) are ignored"], ["The following is 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], @@ -10,113 +10,173 @@ ["See http://r6.ca/blog/20111119T211504Z.html"], ["It is also the first OP_CHECKMULTISIG transaction in standard form"], [[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", true], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], ["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], -["It has an arbitrary extra byte stuffed into the signature at pos length - 2"], +["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", true], +"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"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], + +["As above, but using a OP_1"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], + +["As above, but using a OP_1NEGATE"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], ["The following is c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"], ["It is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)"], [[["406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602", 0, "DUP HASH160 0x14 0xdc44b1164188067c3a32d4780f5996fa14a4f2d9 EQUALVERIFY CHECKSIG"]], -"01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", true], +"01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", "P2SH"], ["A nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], ["Same as above, but with the signature duplicated in the scriptPubKey with the proper pushdata prefix"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], ["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"], ["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"], [[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"], ["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]], -"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", true], +"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "P2SH"], ["The following tests for the presence of a bug in the handling of SIGHASH_SINGLE"], ["It results in signing the constant 1, instead of something generated based on the transaction,"], ["when the input doing the signing has an index greater than the maximum output index"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"]], -"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", true], +"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"], ["An invalid P2SH Transaction"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], -"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", false], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "NONE"], ["A valid P2SH Transaction using the standard transaction type put forth in BIP 16"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", "P2SH"], ["Tests for CheckTransaction()"], ["MAX_MONEY output"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", "P2SH"], ["MAX_MONEY output + 0 output"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", "P2SH"], ["Coinbase of size 2"], ["Note the input is just required to make the tester happy"], [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", true], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", "P2SH"], ["Coinbase of size 100"], ["Note the input is just required to make the tester happy"], [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"], ["Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], - "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", true], + "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"], ["Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], - "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", true], + "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"], ["afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae which has several SIGHASH_SINGLE signatures"], [[["63cfa5a09dc540bf63e53713b82d9ea3692ca97cd608c384f2aa88e51a0aac70", 0, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"], ["04e8d0fcf3846c6734477b98f0f3d4badfb78f020ee097a0be5fe347645b817d", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"], ["ee1377aff5d0579909e11782e1d2f5f7b84d26537be7f5516dd4e43373091f3f", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"]], - "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000", true], + "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000", "P2SH"], ["ddc454a1c0c35c188c98976b17670f69e586d9c0f3593ea879928332f0a069e7, which spends an input that pushes using a PUSHDATA1 that is negative when read as signed"], [[["c5510a5dd97a25f43175af1fe649b707b1df8e1a41489bac33a23087027a2f48", 0, "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG"]], - "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000", true], + "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000", "P2SH"], ["Correct signature order"], ["Note the input is just required to make the tester happy"], [[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]], -"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", true], +"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "P2SH"], ["cc60b1f899ec0a69b7c3f25ddf32c4524096a9c5b01cbd84c6d0312a0c478984, which is a fairly strange transaction which relies on OP_CHECKSIG returning 0 when checking a completely invalid sig of length 0"], [[["cbebc4da731e8995fe97f6fadcd731b36ad40e5ecb31e38e904f6e5982fa09f7", 0, "0x2102085c6600657566acc2d6382a47bc3f324008d2aa10940dd7705a48aa2a5a5e33ac7c2103f5d0fb955f95dd6be6115ce85661db412ec6a08abcbfce7da0ba8297c6cc0ec4ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a5479827701200122a59a5379827701200122a59a6353798277537982778779679a68"]], -"0100000001f709fa82596e4f908ee331cb5e0ed46ab331d7dcfaf697fe95891e73dac4ebcb000000008c20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100a9df60536df5733dd0de6bc921fab0b3eee6426501b43a228afa2c90072eb5ca02201c78b74266fac7d1db5deff080d8a403743203f109fbcabf6d5a760bf87386d20100ffffffff01c075790000000000232103611f9a45c18f28f06f19076ad571c344c82ce8fcfe34464cf8085217a2d294a6ac00000000", true], +"0100000001f709fa82596e4f908ee331cb5e0ed46ab331d7dcfaf697fe95891e73dac4ebcb000000008c20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100a9df60536df5733dd0de6bc921fab0b3eee6426501b43a228afa2c90072eb5ca02201c78b74266fac7d1db5deff080d8a403743203f109fbcabf6d5a760bf87386d20100ffffffff01c075790000000000232103611f9a45c18f28f06f19076ad571c344c82ce8fcfe34464cf8085217a2d294a6ac00000000", "P2SH"], ["Empty pubkey"], [[["229257c295e7f555421c1bfec8538dd30a4b5c37c1c8810bbe83cafa7811652c", 0, "0x00 CHECKSIG NOT"]], -"01000000012c651178faca83be0b81c8c1375c4b0ad38d53c8fe1b1c4255f5e795c25792220000000049483045022100d6044562284ac76c985018fc4a90127847708c9edb280996c507b28babdc4b2a02203d74eca3f1a4d1eea7ff77b528fde6d5dc324ec2dbfdb964ba885f643b9704cd01ffffffff010100000000000000232102c2410f8891ae918cab4ffc4bb4a3b0881be67c7a1e7faa8b5acf9ab8932ec30cac00000000", true], +"01000000012c651178faca83be0b81c8c1375c4b0ad38d53c8fe1b1c4255f5e795c25792220000000049483045022100d6044562284ac76c985018fc4a90127847708c9edb280996c507b28babdc4b2a02203d74eca3f1a4d1eea7ff77b528fde6d5dc324ec2dbfdb964ba885f643b9704cd01ffffffff010100000000000000232102c2410f8891ae918cab4ffc4bb4a3b0881be67c7a1e7faa8b5acf9ab8932ec30cac00000000", "P2SH"], ["Empty signature"], [[["9ca93cfd8e3806b9d9e2ba1cf64e3cc6946ee0119670b1796a09928d14ea25f7", 0, "0x21 0x028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02 CHECKSIG NOT"]], -"0100000001f725ea148d92096a79b1709611e06e94c63c4ef61cbae2d9b906388efd3ca99c000000000100ffffffff0101000000000000002321028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac00000000", true], +"0100000001f725ea148d92096a79b1709611e06e94c63c4ef61cbae2d9b906388efd3ca99c000000000100ffffffff0101000000000000002321028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac00000000", "P2SH"], [[["444e00ed7840d41f20ecd9c11d3f91982326c731a02f3c05748414a4fa9e59be", 0, "1 0x00 0x21 0x02136b04758b0b6e363e7a6fbe83aaf527a153db2b060d36cc29f7f8309ba6e458 2 CHECKMULTISIG"]], -"0100000001be599efaa4148474053c2fa031c7262398913f1dc1d9ec201fd44078ed004e44000000004900473044022022b29706cb2ed9ef0cb3c97b72677ca2dfd7b4160f7b4beb3ba806aa856c401502202d1e52582412eba2ed474f1f437a427640306fd3838725fab173ade7fe4eae4a01ffffffff010100000000000000232103ac4bba7e7ca3e873eea49e08132ad30c7f03640b6539e9b59903cf14fd016bbbac00000000", true], +"0100000001be599efaa4148474053c2fa031c7262398913f1dc1d9ec201fd44078ed004e44000000004900473044022022b29706cb2ed9ef0cb3c97b72677ca2dfd7b4160f7b4beb3ba806aa856c401502202d1e52582412eba2ed474f1f437a427640306fd3838725fab173ade7fe4eae4a01ffffffff010100000000000000232103ac4bba7e7ca3e873eea49e08132ad30c7f03640b6539e9b59903cf14fd016bbbac00000000", "P2SH"], [[["e16abbe80bf30c080f63830c8dbf669deaef08957446e95940227d8c5e6db612", 0, "1 0x21 0x03905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9f 0x00 2 CHECKMULTISIG"]], -"010000000112b66d5e8c7d224059e946749508efea9d66bf8d0c83630f080cf30be8bb6ae100000000490047304402206ffe3f14caf38ad5c1544428e99da76ffa5455675ec8d9780fac215ca17953520220779502985e194d84baa36b9bd40a0dbd981163fa191eb884ae83fc5bd1c86b1101ffffffff010100000000000000232103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9fac00000000", true], +"010000000112b66d5e8c7d224059e946749508efea9d66bf8d0c83630f080cf30be8bb6ae100000000490047304402206ffe3f14caf38ad5c1544428e99da76ffa5455675ec8d9780fac215ca17953520220779502985e194d84baa36b9bd40a0dbd981163fa191eb884ae83fc5bd1c86b1101ffffffff010100000000000000232103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9fac00000000", "P2SH"], [[["ebbcf4bfce13292bd791d6a65a2a858d59adbf737e387e40370d4e64cc70efb0", 0, "2 0x21 0x033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194 0x21 0x03a88b326f8767f4f192ce252afe33c94d25ab1d24f27f159b3cb3aa691ffe1423 2 CHECKMULTISIG NOT"]], -"0100000001b0ef70cc644e0d37407e387e73bfad598d852a5aa6d691d72b2913cebff4bceb000000004a00473044022068cd4851fc7f9a892ab910df7a24e616f293bcb5c5fbdfbc304a194b26b60fba022078e6da13d8cb881a22939b952c24f88b97afd06b4c47a47d7f804c9a352a6d6d0100ffffffff0101000000000000002321033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194ac00000000", true], +"0100000001b0ef70cc644e0d37407e387e73bfad598d852a5aa6d691d72b2913cebff4bceb000000004a00473044022068cd4851fc7f9a892ab910df7a24e616f293bcb5c5fbdfbc304a194b26b60fba022078e6da13d8cb881a22939b952c24f88b97afd06b4c47a47d7f804c9a352a6d6d0100ffffffff0101000000000000002321033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194ac00000000", "P2SH"], [[["ba4cd7ae2ad4d4d13ebfc8ab1d93a63e4a6563f25089a18bf0fc68f282aa88c1", 0, "2 0x21 0x037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1 0x21 0x02edc823cd634f2c4033d94f5755207cb6b60c4b1f1f056ad7471c47de5f2e4d50 2 CHECKMULTISIG NOT"]], -"0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba000000004b0000483045022100940378576e069aca261a6b26fb38344e4497ca6751bb10905c76bb689f4222b002204833806b014c26fd801727b792b1260003c55710f87c5adbd7a9cb57446dbc9801ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac00000000", true], +"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/netbase_tests.cpp b/src/test/netbase_tests.cpp index 4321852d11..c26e738384 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -102,4 +102,41 @@ BOOST_AUTO_TEST_CASE(onioncat_test) BOOST_CHECK(addr1.IsRoutable()); } +BOOST_AUTO_TEST_CASE(subnet_test) +{ + BOOST_CHECK(CSubNet("1.2.3.0/24") == CSubNet("1.2.3.0/255.255.255.0")); + BOOST_CHECK(CSubNet("1.2.3.0/24") != CSubNet("1.2.4.0/255.255.255.0")); + BOOST_CHECK(CSubNet("1.2.3.0/24").Match(CNetAddr("1.2.3.4"))); + BOOST_CHECK(!CSubNet("1.2.2.0/24").Match(CNetAddr("1.2.3.4"))); + BOOST_CHECK(CSubNet("1.2.3.4").Match(CNetAddr("1.2.3.4"))); + BOOST_CHECK(CSubNet("1.2.3.4/32").Match(CNetAddr("1.2.3.4"))); + BOOST_CHECK(!CSubNet("1.2.3.4").Match(CNetAddr("5.6.7.8"))); + BOOST_CHECK(!CSubNet("1.2.3.4/32").Match(CNetAddr("5.6.7.8"))); + BOOST_CHECK(CSubNet("::ffff:127.0.0.1").Match(CNetAddr("127.0.0.1"))); + BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8").Match(CNetAddr("1:2:3:4:5:6:7:8"))); + BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8").Match(CNetAddr("1:2:3:4:5:6:7:9"))); + BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:0/112").Match(CNetAddr("1:2:3:4:5:6:7:1234"))); + // All-Matching IPv6 Matches arbitrary IPv4 and IPv6 + BOOST_CHECK(CSubNet("::/0").Match(CNetAddr("1:2:3:4:5:6:7:1234"))); + BOOST_CHECK(CSubNet("::/0").Match(CNetAddr("1.2.3.4"))); + // All-Matching IPv4 does not Match IPv6 + BOOST_CHECK(!CSubNet("0.0.0.0/0").Match(CNetAddr("1:2:3:4:5:6:7:1234"))); + // Invalid subnets Match nothing (not even invalid addresses) + BOOST_CHECK(!CSubNet().Match(CNetAddr("1.2.3.4"))); + BOOST_CHECK(!CSubNet("").Match(CNetAddr("4.5.6.7"))); + BOOST_CHECK(!CSubNet("bloop").Match(CNetAddr("0.0.0.0"))); + BOOST_CHECK(!CSubNet("bloop").Match(CNetAddr("hab"))); + // Check valid/invalid + BOOST_CHECK(CSubNet("1.2.3.0/0").IsValid()); + BOOST_CHECK(!CSubNet("1.2.3.0/-1").IsValid()); + BOOST_CHECK(CSubNet("1.2.3.0/32").IsValid()); + BOOST_CHECK(!CSubNet("1.2.3.0/33").IsValid()); + BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/0").IsValid()); + BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/33").IsValid()); + BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8/-1").IsValid()); + BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/128").IsValid()); + BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8/129").IsValid()); + BOOST_CHECK(!CSubNet("fuzzy").IsValid()); +} + BOOST_AUTO_TEST_SUITE_END() 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_tests.cpp b/src/test/rpc_tests.cpp index 5bc38ce2de..107c0f06e7 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -6,6 +6,7 @@ #include "rpcclient.h" #include "base58.h" +#include "netbase.h" #include <boost/algorithm/string.hpp> #include <boost/test/unit_test.hpp> @@ -138,4 +139,19 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values) BOOST_CHECK(AmountFromValue(ValueFromString("20999999.99999999")) == 2099999999999999LL); } +BOOST_AUTO_TEST_CASE(rpc_boostasiotocnetaddr) +{ + // Check IPv4 addresses + BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("1.2.3.4")).ToString(), "1.2.3.4"); + BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("127.0.0.1")).ToString(), "127.0.0.1"); + // Check IPv6 addresses + BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("::1")).ToString(), "::1"); + BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("123:4567:89ab:cdef:123:4567:89ab:cdef")).ToString(), + "123:4567:89ab:cdef:123:4567:89ab:cdef"); + // v4 compatible must be interpreted as IPv4 + BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("::0:127.0.0.1")).ToString(), "127.0.0.1"); + // v4 mapped must be interpreted as IPv4 + BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("::ffff:127.0.0.1")).ToString(), "127.0.0.1"); +} + BOOST_AUTO_TEST_SUITE_END() 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 7bc2bfb6dd..cba582e941 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -67,7 +67,11 @@ ParseScript(string s) BOOST_FOREACH(string w, words) { - if (all(w, is_digit()) || + if (w.size() == 0) + { + // Empty string, ignore. (boost::split given '' will return one word) + } + else if (all(w, is_digit()) || (starts_with(w, "-") && all(string(w.begin()+1, w.end()), is_digit()))) { // Number @@ -236,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; @@ -270,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; @@ -341,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/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp new file mode 100644 index 0000000000..cd194cc4d9 --- /dev/null +++ b/src/test/scriptnum_tests.cpp @@ -0,0 +1,196 @@ +// Copyright (c) 2012-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 "bignum.h" +#include "script.h" +#include <boost/test/unit_test.hpp> +#include <limits.h> +#include <stdint.h> +BOOST_AUTO_TEST_SUITE(scriptnum_tests) + +static const int64_t values[] = \ +{ 0, 1, CHAR_MIN, CHAR_MAX, UCHAR_MAX, SHRT_MIN, USHRT_MAX, INT_MIN, INT_MAX, UINT_MAX, LONG_MIN, LONG_MAX }; +static const int64_t offsets[] = { 1, 0x79, 0x80, 0x81, 0xFF, 0x7FFF, 0x8000, 0xFFFF, 0x10000}; + +static bool verify(const CBigNum& bignum, const CScriptNum& scriptnum) +{ + return bignum.getvch() == scriptnum.getvch() && bignum.getint() == scriptnum.getint(); +} + +static void CheckCreateVch(const int64_t& num) +{ + CBigNum bignum(num); + CScriptNum scriptnum(num); + BOOST_CHECK(verify(bignum, scriptnum)); + + CBigNum bignum2(bignum.getvch()); + CScriptNum scriptnum2(scriptnum.getvch()); + BOOST_CHECK(verify(bignum2, scriptnum2)); + + CBigNum bignum3(scriptnum2.getvch()); + CScriptNum scriptnum3(bignum2.getvch()); + BOOST_CHECK(verify(bignum3, scriptnum3)); +} + +static void CheckCreateInt(const int64_t& num) +{ + CBigNum bignum(num); + CScriptNum scriptnum(num); + BOOST_CHECK(verify(bignum, scriptnum)); + BOOST_CHECK(verify(bignum.getint(), CScriptNum(scriptnum.getint()))); + BOOST_CHECK(verify(scriptnum.getint(), CScriptNum(bignum.getint()))); + BOOST_CHECK(verify(CBigNum(scriptnum.getint()).getint(), CScriptNum(CScriptNum(bignum.getint()).getint()))); +} + + +static void CheckAdd(const int64_t& num1, const int64_t& num2) +{ + const CBigNum bignum1(num1); + const CBigNum bignum2(num2); + const CScriptNum scriptnum1(num1); + const CScriptNum scriptnum2(num2); + CBigNum bignum3(num1); + CBigNum bignum4(num1); + CScriptNum scriptnum3(num1); + CScriptNum scriptnum4(num1); + + // int64_t overflow is undefined. + bool invalid = (((num2 > 0) && (num1 > (std::numeric_limits<int64_t>::max() - num2))) || + ((num2 < 0) && (num1 < (std::numeric_limits<int64_t>::min() - num2)))); + if (!invalid) + { + BOOST_CHECK(verify(bignum1 + bignum2, scriptnum1 + scriptnum2)); + BOOST_CHECK(verify(bignum1 + bignum2, scriptnum1 + num2)); + BOOST_CHECK(verify(bignum1 + bignum2, scriptnum2 + num1)); + } +} + +static void CheckNegate(const int64_t& num) +{ + const CBigNum bignum(num); + const CScriptNum scriptnum(num); + + // -INT64_MIN is undefined + if (num != std::numeric_limits<int64_t>::min()) + BOOST_CHECK(verify(-bignum, -scriptnum)); +} + +static void CheckSubtract(const int64_t& num1, const int64_t& num2) +{ + const CBigNum bignum1(num1); + const CBigNum bignum2(num2); + const CScriptNum scriptnum1(num1); + const CScriptNum scriptnum2(num2); + bool invalid = false; + + // int64_t overflow is undefined. + invalid = ((num2 > 0 && num1 < std::numeric_limits<int64_t>::min() + num2) || + (num2 < 0 && num1 > std::numeric_limits<int64_t>::max() + num2)); + if (!invalid) + { + BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - scriptnum2)); + BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - num2)); + } + + invalid = ((num1 > 0 && num2 < std::numeric_limits<int64_t>::min() + num1) || + (num1 < 0 && num2 > std::numeric_limits<int64_t>::max() + num1)); + if (!invalid) + { + BOOST_CHECK(verify(bignum2 - bignum1, scriptnum2 - scriptnum1)); + BOOST_CHECK(verify(bignum2 - bignum1, scriptnum2 - num1)); + } +} + +static void CheckCompare(const int64_t& num1, const int64_t& num2) +{ + const CBigNum bignum1(num1); + const CBigNum bignum2(num2); + const CScriptNum scriptnum1(num1); + const CScriptNum scriptnum2(num2); + + BOOST_CHECK((bignum1 == bignum1) == (scriptnum1 == scriptnum1)); + BOOST_CHECK((bignum1 != bignum1) == (scriptnum1 != scriptnum1)); + BOOST_CHECK((bignum1 < bignum1) == (scriptnum1 < scriptnum1)); + BOOST_CHECK((bignum1 > bignum1) == (scriptnum1 > scriptnum1)); + BOOST_CHECK((bignum1 >= bignum1) == (scriptnum1 >= scriptnum1)); + BOOST_CHECK((bignum1 <= bignum1) == (scriptnum1 <= scriptnum1)); + + BOOST_CHECK((bignum1 == bignum1) == (scriptnum1 == num1)); + BOOST_CHECK((bignum1 != bignum1) == (scriptnum1 != num1)); + BOOST_CHECK((bignum1 < bignum1) == (scriptnum1 < num1)); + BOOST_CHECK((bignum1 > bignum1) == (scriptnum1 > num1)); + BOOST_CHECK((bignum1 >= bignum1) == (scriptnum1 >= num1)); + BOOST_CHECK((bignum1 <= bignum1) == (scriptnum1 <= num1)); + + BOOST_CHECK((bignum1 == bignum2) == (scriptnum1 == scriptnum2)); + BOOST_CHECK((bignum1 != bignum2) == (scriptnum1 != scriptnum2)); + BOOST_CHECK((bignum1 < bignum2) == (scriptnum1 < scriptnum2)); + BOOST_CHECK((bignum1 > bignum2) == (scriptnum1 > scriptnum2)); + BOOST_CHECK((bignum1 >= bignum2) == (scriptnum1 >= scriptnum2)); + BOOST_CHECK((bignum1 <= bignum2) == (scriptnum1 <= scriptnum2)); + + BOOST_CHECK((bignum1 == bignum2) == (scriptnum1 == num2)); + BOOST_CHECK((bignum1 != bignum2) == (scriptnum1 != num2)); + BOOST_CHECK((bignum1 < bignum2) == (scriptnum1 < num2)); + BOOST_CHECK((bignum1 > bignum2) == (scriptnum1 > num2)); + BOOST_CHECK((bignum1 >= bignum2) == (scriptnum1 >= num2)); + BOOST_CHECK((bignum1 <= bignum2) == (scriptnum1 <= num2)); +} + +static void RunCreate(const int64_t& num) +{ + CheckCreateInt(num); + CScriptNum scriptnum(num); + if (scriptnum.getvch().size() <= CScriptNum::nMaxNumSize) + CheckCreateVch(num); + else + { + BOOST_CHECK_THROW (CheckCreateVch(num), scriptnum_error); + } +} + +static void RunOperators(const int64_t& num1, const int64_t& num2) +{ + CheckAdd(num1, num2); + CheckSubtract(num1, num2); + CheckNegate(num1); + CheckCompare(num1, num2); +} + +BOOST_AUTO_TEST_CASE(creation) +{ + for(size_t i = 0; i < sizeof(values) / sizeof(values[0]); ++i) + { + for(size_t j = 0; j < sizeof(offsets) / sizeof(offsets[0]); ++j) + { + RunCreate(values[i]); + RunCreate(values[i] + offsets[j]); + RunCreate(values[i] - offsets[j]); + } + } +} + +BOOST_AUTO_TEST_CASE(operators) +{ + for(size_t i = 0; i < sizeof(values) / sizeof(values[0]); ++i) + { + for(size_t j = 0; j < sizeof(offsets) / sizeof(offsets[0]); ++j) + { + RunOperators(values[i], values[i]); + RunOperators(values[i], -values[i]); + RunOperators(values[i], values[j]); + RunOperators(values[i], -values[j]); + RunOperators(values[i] + values[j], values[j]); + RunOperators(values[i] + values[j], -values[j]); + RunOperators(values[i] - values[j], values[j]); + RunOperators(values[i] - values[j], -values[j]); + RunOperators(values[i] + values[j], values[i] + values[j]); + RunOperators(values[i] + values[j], values[i] - values[j]); + RunOperators(values[i] - values[j], values[i] + values[j]); + RunOperators(values[i] - values[j], values[i] - values[j]); + } + } +} + +BOOST_AUTO_TEST_SUITE_END() 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 24647950c4..238033f407 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -13,16 +13,45 @@ #include <map> #include <string> +#include <boost/algorithm/string/classification.hpp> +#include <boost/algorithm/string/split.hpp> #include <boost/test/unit_test.hpp> #include "json/json_spirit_writer_template.h" using namespace std; using namespace json_spirit; +using namespace boost::algorithm; // In script_tests.cpp extern Array read_json(const std::string& jsondata); extern CScript ParseScript(string s); +unsigned int ParseFlags(string strFlags){ + unsigned int flags = 0; + vector<string> words; + split(words, strFlags, is_any_of(",")); + + // Note how NOCACHE is not included as it is a runtime-only flag. + static map<string, unsigned int> mapFlagNames; + if (mapFlagNames.size() == 0) + { + mapFlagNames["NONE"] = SCRIPT_VERIFY_NONE; + mapFlagNames["P2SH"] = SCRIPT_VERIFY_P2SH; + mapFlagNames["STRICTENC"] = SCRIPT_VERIFY_STRICTENC; + mapFlagNames["LOW_S"] = SCRIPT_VERIFY_LOW_S; + mapFlagNames["NULLDUMMY"] = SCRIPT_VERIFY_NULLDUMMY; + } + + BOOST_FOREACH(string word, words) + { + if (!mapFlagNames.count(word)) + BOOST_ERROR("Bad test: unknown verification flag '" << word << "'"); + flags |= mapFlagNames[word]; + } + + return flags; +} + BOOST_AUTO_TEST_SUITE(transaction_tests) BOOST_AUTO_TEST_CASE(tx_valid) @@ -30,8 +59,10 @@ BOOST_AUTO_TEST_CASE(tx_valid) // Read tests from test/data/tx_valid.json // Format is an array of arrays // Inner arrays are either [ "comment" ] - // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, enforceP2SH + // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, verifyFlags // ... where all scripts are stringified scripts. + // + // verifyFlags is a comma separated list of script verification flags to apply, or "NONE" Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid))); BOOST_FOREACH(Value& tv, tests) @@ -40,7 +71,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) string strTest = write_string(tv, false); if (test[0].type() == array_type) { - if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type) + if (test.size() != 3 || test[1].type() != str_type || test[2].type() != str_type) { BOOST_ERROR("Bad test: " << strTest); continue; @@ -88,7 +119,10 @@ BOOST_AUTO_TEST_CASE(tx_valid) break; } - BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool() ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0), strTest); + unsigned int verify_flags = ParseFlags(test[2].get_str()); + BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], + tx, i, verify_flags, 0), + strTest); } } } @@ -99,8 +133,10 @@ BOOST_AUTO_TEST_CASE(tx_invalid) // Read tests from test/data/tx_invalid.json // Format is an array of arrays // Inner arrays are either [ "comment" ] - // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, enforceP2SH + // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, verifyFlags // ... where all scripts are stringified scripts. + // + // verifyFlags is a comma separated list of script verification flags to apply, or "NONE" Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid))); BOOST_FOREACH(Value& tv, tests) @@ -109,7 +145,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) string strTest = write_string(tv, false); if (test[0].type() == array_type) { - if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type) + if (test.size() != 3 || test[1].type() != str_type || test[2].type() != str_type) { BOOST_ERROR("Bad test: " << strTest); continue; @@ -156,7 +192,9 @@ BOOST_AUTO_TEST_CASE(tx_invalid) break; } - fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool() ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0); + unsigned int verify_flags = ParseFlags(test[2].get_str()); + fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], + tx, i, verify_flags, 0); } BOOST_CHECK_MESSAGE(!fValid, strTest); @@ -170,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."); @@ -186,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: @@ -223,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; @@ -258,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/uint256_tests.cpp b/src/test/uint256_tests.cpp index 815babf107..4b1a2ae58f 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -160,11 +160,11 @@ BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality tmpS = ~R2S; BOOST_CHECK(tmpS == ~R2S); tmpS = ~MaxS; BOOST_CHECK(tmpS == ~MaxS); - // Wrong length must give 0 - BOOST_CHECK(uint256(std::vector<unsigned char>(OneArray,OneArray+31)) == 0); - BOOST_CHECK(uint256(std::vector<unsigned char>(OneArray,OneArray+20)) == 0); - BOOST_CHECK(uint160(std::vector<unsigned char>(OneArray,OneArray+32)) == 0); - BOOST_CHECK(uint160(std::vector<unsigned char>(OneArray,OneArray+19)) == 0); + // Wrong length must throw exception. + BOOST_CHECK_THROW(uint256(std::vector<unsigned char>(OneArray,OneArray+31)), uint_error); + BOOST_CHECK_THROW(uint256(std::vector<unsigned char>(OneArray,OneArray+20)), uint_error); + BOOST_CHECK_THROW(uint160(std::vector<unsigned char>(OneArray,OneArray+32)), uint_error); + BOOST_CHECK_THROW(uint160(std::vector<unsigned char>(OneArray,OneArray+19)), uint_error); } void shiftArrayRight(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift) @@ -482,6 +482,77 @@ BOOST_AUTO_TEST_CASE( plusMinus ) } +BOOST_AUTO_TEST_CASE( multiply ) +{ + BOOST_CHECK((R1L * R1L).ToString() == "62a38c0486f01e45879d7910a7761bf30d5237e9873f9bff3642a732c4d84f10"); + BOOST_CHECK((R1L * R2L).ToString() == "de37805e9986996cfba76ff6ba51c008df851987d9dd323f0e5de07760529c40"); + BOOST_CHECK((R1L * ZeroL) == ZeroL); + BOOST_CHECK((R1L * OneL) == R1L); + BOOST_CHECK((R1L * MaxL) == -R1L); + BOOST_CHECK((R2L * R1L) == (R1L * R2L)); + BOOST_CHECK((R2L * R2L).ToString() == "ac8c010096767d3cae5005dec28bb2b45a1d85ab7996ccd3e102a650f74ff100"); + BOOST_CHECK((R2L * ZeroL) == ZeroL); + BOOST_CHECK((R2L * OneL) == R2L); + BOOST_CHECK((R2L * MaxL) == -R2L); + + BOOST_CHECK((R1S * R1S).ToString() == "a7761bf30d5237e9873f9bff3642a732c4d84f10"); + BOOST_CHECK((R1S * R2S).ToString() == "ba51c008df851987d9dd323f0e5de07760529c40"); + BOOST_CHECK((R1S * ZeroS) == ZeroS); + BOOST_CHECK((R1S * OneS) == R1S); + BOOST_CHECK((R1S * MaxS) == -R1S); + BOOST_CHECK((R2S * R1S) == (R1S * R2S)); + BOOST_CHECK((R2S * R2S).ToString() == "c28bb2b45a1d85ab7996ccd3e102a650f74ff100"); + BOOST_CHECK((R2S * ZeroS) == ZeroS); + BOOST_CHECK((R2S * OneS) == R2S); + BOOST_CHECK((R2S * MaxS) == -R2S); + + BOOST_CHECK(MaxL * MaxL == OneL); + BOOST_CHECK(MaxS * MaxS == OneS); + + BOOST_CHECK((R1L * 0) == 0); + BOOST_CHECK((R1L * 1) == R1L); + BOOST_CHECK((R1L * 3).ToString() == "7759b1c0ed14047f961ad09b20ff83687876a0181a367b813634046f91def7d4"); + BOOST_CHECK((R2L * 0x87654321UL).ToString() == "23f7816e30c4ae2017257b7a0fa64d60402f5234d46e746b61c960d09a26d070"); + BOOST_CHECK((R1S * 0) == 0); + BOOST_CHECK((R1S * 1) == R1S); + BOOST_CHECK((R1S * 7).ToString() == "f7a987f3c3bf758d927f202d7e795faeff084244"); + BOOST_CHECK((R2S * 0xFFFFFFFFUL).ToString() == "1c6f6c930353e17f7d6127213bb18d2883e2cd90"); +} + +BOOST_AUTO_TEST_CASE( divide ) +{ + uint256 D1L("AD7133AC1977FA2B7"); + uint256 D2L("ECD751716"); + BOOST_CHECK((R1L / D1L).ToString() == "00000000000000000b8ac01106981635d9ed112290f8895545a7654dde28fb3a"); + BOOST_CHECK((R1L / D2L).ToString() == "000000000873ce8efec5b67150bad3aa8c5fcb70e947586153bf2cec7c37c57a"); + BOOST_CHECK(R1L / OneL == R1L); + BOOST_CHECK(R1L / MaxL == ZeroL); + BOOST_CHECK(MaxL / R1L == 2); + BOOST_CHECK_THROW(R1L / ZeroL, uint_error); + BOOST_CHECK((R2L / D1L).ToString() == "000000000000000013e1665895a1cc981de6d93670105a6b3ec3b73141b3a3c5"); + BOOST_CHECK((R2L / D2L).ToString() == "000000000e8f0abe753bb0afe2e9437ee85d280be60882cf0bd1aaf7fa3cc2c4"); + BOOST_CHECK(R2L / OneL == R2L); + BOOST_CHECK(R2L / MaxL == ZeroL); + BOOST_CHECK(MaxL / R2L == 1); + BOOST_CHECK_THROW(R2L / ZeroL, uint_error); + + uint160 D1S("D3C5EDCDEA54EB92679F0A4B4"); + uint160 D2S("13037"); + BOOST_CHECK((R1S / D1S).ToString() == "0000000000000000000000000db9af3beade6c02"); + BOOST_CHECK((R1S / D2S).ToString() == "000098dfb6cc40ca592bf74366794f298ada205c"); + BOOST_CHECK(R1S / OneS == R1S); + BOOST_CHECK(R1S / MaxS == ZeroS); + BOOST_CHECK(MaxS / R1S == 1); + BOOST_CHECK_THROW(R1S / ZeroS, uint_error); + BOOST_CHECK((R2S / D1S).ToString() == "0000000000000000000000000c5608e781182047"); + BOOST_CHECK((R2S / D2S).ToString() == "00008966751b7187c3c67c1fda5cea7db2c1c069"); + BOOST_CHECK(R2S / OneS == R2S); + BOOST_CHECK(R2S / MaxS == ZeroS); + BOOST_CHECK(MaxS / R2S == 1); + BOOST_CHECK_THROW(R2S / ZeroS, uint_error); +} + + bool almostEqual(double d1, double d2) { return fabs(d1-d2) <= 4*fabs(d1)*std::numeric_limits<double>::epsilon(); @@ -604,6 +675,135 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G } } +BOOST_AUTO_TEST_CASE(bignum_SetCompact) +{ + uint256 num; + bool fNegative; + bool fOverflow; + num.SetCompact(0, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x00123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x01003456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x02000056, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x03000000, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x04000000, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x00923456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x01803456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x02800056, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x03800000, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x04800000, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x01123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000012"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + // Make sure that we don't generate compacts with the 0x00800000 bit set + num = 0x80; + BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000U); + + num.SetCompact(0x01fedcba, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "000000000000000000000000000000000000000000000000000000000000007e"); + BOOST_CHECK_EQUAL(num.GetCompact(true), 0x01fe0000U); + BOOST_CHECK_EQUAL(fNegative, true); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x02123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000001234"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x03123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000123456"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x04123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000012345600"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x04923456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000012345600"); + BOOST_CHECK_EQUAL(num.GetCompact(true), 0x04923456U); + BOOST_CHECK_EQUAL(fNegative, true); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x05009234, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000092340000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x20123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "1234560000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0xff123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, true); +} + + BOOST_AUTO_TEST_CASE( getmaxcoverage ) // some more tests just to get 100% coverage { // ~R1L give a base_uint<256> diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index b8f107f644..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) @@ -165,17 +163,6 @@ BOOST_AUTO_TEST_CASE(util_GetArg) BOOST_CHECK_EQUAL(GetBoolArg("booltest4", false), true); } -BOOST_AUTO_TEST_CASE(util_WildcardMatch) -{ - BOOST_CHECK(WildcardMatch("127.0.0.1", "*")); - BOOST_CHECK(WildcardMatch("127.0.0.1", "127.*")); - BOOST_CHECK(WildcardMatch("abcdef", "a?cde?")); - BOOST_CHECK(!WildcardMatch("abcdef", "a?cde??")); - BOOST_CHECK(WildcardMatch("abcdef", "a*f")); - BOOST_CHECK(!WildcardMatch("abcdef", "a*x")); - BOOST_CHECK(WildcardMatch("", "*")); -} - BOOST_AUTO_TEST_CASE(util_FormatMoney) { BOOST_CHECK_EQUAL(FormatMoney(0, false), "0.00"); @@ -321,15 +308,15 @@ BOOST_AUTO_TEST_CASE(strprintf_numbers) size_t st = 12345678; /* unsigned size_t test value */ ssize_t sst = -12345678; /* signed size_t test value */ - BOOST_CHECK(strprintf("%s %"PRIszd" %s", B, sst, E) == B" -12345678 "E); - BOOST_CHECK(strprintf("%s %"PRIszu" %s", B, st, E) == B" 12345678 "E); - BOOST_CHECK(strprintf("%s %"PRIszx" %s", B, st, E) == B" bc614e "E); + BOOST_CHECK(strprintf("%s %d %s", B, sst, E) == B" -12345678 "E); + BOOST_CHECK(strprintf("%s %u %s", B, st, E) == B" 12345678 "E); + BOOST_CHECK(strprintf("%s %x %s", B, st, E) == B" bc614e "E); ptrdiff_t pt = 87654321; /* positive ptrdiff_t test value */ ptrdiff_t spt = -87654321; /* negative ptrdiff_t test value */ - BOOST_CHECK(strprintf("%s %"PRIpdd" %s", B, spt, E) == B" -87654321 "E); - BOOST_CHECK(strprintf("%s %"PRIpdu" %s", B, pt, E) == B" 87654321 "E); - BOOST_CHECK(strprintf("%s %"PRIpdx" %s", B, pt, E) == B" 5397fb1 "E); + BOOST_CHECK(strprintf("%s %d %s", B, spt, E) == B" -87654321 "E); + BOOST_CHECK(strprintf("%s %u %s", B, pt, E) == B" 87654321 "E); + BOOST_CHECK(strprintf("%s %x %s", B, pt, E) == B" 5397fb1 "E); } #undef B #undef E @@ -342,4 +329,37 @@ BOOST_AUTO_TEST_CASE(gettime) BOOST_CHECK((GetTime() & ~0xFFFFFFFFLL) == 0); } +BOOST_AUTO_TEST_CASE(test_ParseInt32) +{ + int32_t n; + // Valid values + BOOST_CHECK(ParseInt32("1234", NULL)); + BOOST_CHECK(ParseInt32("0", &n) && n == 0); + BOOST_CHECK(ParseInt32("1234", &n) && n == 1234); + BOOST_CHECK(ParseInt32("01234", &n) && n == 1234); // no octal + BOOST_CHECK(ParseInt32("2147483647", &n) && n == 2147483647); + BOOST_CHECK(ParseInt32("-2147483648", &n) && n == -2147483648); + BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234); + // Invalid values + BOOST_CHECK(!ParseInt32("1a", &n)); + BOOST_CHECK(!ParseInt32("aap", &n)); + BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex + // Overflow and underflow + BOOST_CHECK(!ParseInt32("-2147483649", NULL)); + BOOST_CHECK(!ParseInt32("2147483648", NULL)); + BOOST_CHECK(!ParseInt32("-32482348723847471234", NULL)); + 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 cb92922a35..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); @@ -73,12 +74,6 @@ bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) return Write(make_pair('b', blockindex.GetBlockHash()), blockindex); } -bool CBlockTreeDB::WriteBestInvalidWork(const CBigNum& bnBestInvalidWork) -{ - // Obsolete; only written for backward compatibility. - return Write('I', bnBestInvalidWork); -} - bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) { return Write(make_pair('f', nFile), info); } @@ -218,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 5eb5731db3..7d670c2542 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -14,7 +14,6 @@ #include <utility> #include <vector> -class CBigNum; class CCoins; class uint256; @@ -38,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); }; @@ -52,7 +51,6 @@ private: void operator=(const CBlockTreeDB&); public: bool WriteBlockIndex(const CDiskBlockIndex& blockindex); - bool WriteBestInvalidWork(const CBigNum& bnBestInvalidWork); bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo); bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo); bool ReadLastBlockFile(int &nFile); 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 ba903bc8fc..82db7758c9 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -1,35 +1,61 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin developers +// 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_UINT256_H #define BITCOIN_UINT256_H +#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) {} +}; -/** Base class without constructors for uint256 and uint160. - * This makes the compiler let you use it in a union. - */ +/** Template base class for unsigned big integers. */ template<unsigned int BITS> class base_uint { -protected: +private: enum { WIDTH=BITS/32 }; uint32_t pn[WIDTH]; public: + base_uint() + { + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + } + + base_uint(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + } + + base_uint& operator=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + return *this; + } + + base_uint(uint64_t b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + } + + explicit base_uint(const std::string& str); + explicit base_uint(const std::vector<unsigned char>& vch); + bool operator!() const { for (int i = 0; i < WIDTH; i++) @@ -55,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) { @@ -110,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) { @@ -178,6 +164,9 @@ public: 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++() { @@ -213,134 +202,32 @@ public: return ret; } - - friend inline bool operator<(const base_uint& a, const base_uint& b) - { - for (int i = base_uint::WIDTH-1; i >= 0; i--) - { - if (a.pn[i] < b.pn[i]) - return true; - else if (a.pn[i] > b.pn[i]) - return false; - } - return false; - } - - friend inline bool operator<=(const base_uint& a, const base_uint& b) - { - for (int i = base_uint::WIDTH-1; i >= 0; i--) - { - if (a.pn[i] < b.pn[i]) - return true; - else if (a.pn[i] > b.pn[i]) - return false; - } - return true; - } - - friend inline bool operator>(const base_uint& a, const base_uint& b) - { - for (int i = base_uint::WIDTH-1; i >= 0; i--) - { - if (a.pn[i] > b.pn[i]) - return true; - else if (a.pn[i] < b.pn[i]) - return false; - } - return false; - } - - friend inline bool operator>=(const base_uint& a, const base_uint& b) - { - for (int i = base_uint::WIDTH-1; i >= 0; i--) - { - if (a.pn[i] > b.pn[i]) - return true; - else if (a.pn[i] < b.pn[i]) - return false; - } - return true; - } - - friend inline bool operator==(const base_uint& a, const base_uint& b) - { - for (int i = 0; i < base_uint::WIDTH; i++) - if (a.pn[i] != b.pn[i]) - return false; - return true; - } - - friend inline bool operator==(const base_uint& a, uint64_t b) - { - if (a.pn[0] != (unsigned int)b) - return false; - if (a.pn[1] != (unsigned int)(b >> 32)) - return false; - for (int i = 2; i < base_uint::WIDTH; i++) - if (a.pn[i] != 0) - return false; - return true; - } - - friend inline bool operator!=(const base_uint& a, const base_uint& b) - { - return (!(a == b)); - } - - friend inline bool operator!=(const base_uint& a, uint64_t b) - { - return (!(a == 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()); - } + 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; } + 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; } + 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; } + 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, int shift) { return base_uint(a) >>= shift; } + friend inline const base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; } + friend inline const base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; } + friend inline bool operator==(const base_uint& a, const base_uint& b) { return a.CompareTo(b) == 0; } + friend inline bool operator!=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) != 0; } + friend inline bool operator>(const base_uint& a, const base_uint& b) { return a.CompareTo(b) > 0; } + friend inline bool operator<(const base_uint& a, const base_uint& b) { return a.CompareTo(b) < 0; } + friend inline bool operator>=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) >= 0; } + friend inline bool operator<=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) <= 0; } + 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; + void SetHex(const char* psz); + void SetHex(const std::string& str); + std::string ToString() const; unsigned char* begin() { @@ -367,269 +254,74 @@ public: return sizeof(pn); } + // Returns the position of the highest bit set plus one, or zero if the + // value is zero. + unsigned int bits() const; + uint64_t GetLow64() const { assert(WIDTH >= 2); return pn[0] | (uint64_t)pn[1] << 32; } -// unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const unsigned int GetSerializeSize(int nType, int nVersion) const { return sizeof(pn); } template<typename Stream> -// void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const void Serialize(Stream& s, int nType, int nVersion) const { s.write((char*)pn, sizeof(pn)); } template<typename Stream> -// void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) void Unserialize(Stream& s, int nType, int nVersion) { s.read((char*)pn, sizeof(pn)); } - - - friend class uint160; - friend class uint256; }; -typedef base_uint<160> base_uint160; -typedef base_uint<256> base_uint256; - - - -// -// uint160 and uint256 could be implemented as templates, but to keep -// compile errors and debugging cleaner, they're copy and pasted. -// - - - -////////////////////////////////////////////////////////////////////////////// -// -// uint160 -// - -/** 160-bit unsigned integer */ -class uint160 : public base_uint160 -{ +/** 160-bit unsigned big integer. */ +class uint160 : public base_uint<160> { public: - typedef base_uint160 basetype; - - uint160() - { - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - } - - uint160(const basetype& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - } - - uint160& operator=(const basetype& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - return *this; - } - - uint160(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - } - - uint160& operator=(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - return *this; - } - - explicit uint160(const std::string& str) - { - SetHex(str); - } - - explicit uint160(const std::vector<unsigned char>& vch) - { - if (vch.size() == sizeof(pn)) - memcpy(pn, &vch[0], sizeof(pn)); - else - *this = 0; - } + uint160() {} + uint160(const base_uint<160>& b) : base_uint<160>(b) {} + uint160(uint64_t b) : base_uint<160>(b) {} + explicit uint160(const std::string& str) : base_uint<160>(str) {} + explicit uint160(const std::vector<unsigned char>& vch) : base_uint<160>(vch) {} }; -inline bool operator==(const uint160& a, uint64_t b) { return (base_uint160)a == b; } -inline bool operator!=(const uint160& a, uint64_t b) { return (base_uint160)a != b; } -inline const uint160 operator<<(const base_uint160& a, unsigned int shift) { return uint160(a) <<= shift; } -inline const uint160 operator>>(const base_uint160& a, unsigned int shift) { return uint160(a) >>= shift; } -inline const uint160 operator<<(const uint160& a, unsigned int shift) { return uint160(a) <<= shift; } -inline const uint160 operator>>(const uint160& a, unsigned int shift) { return uint160(a) >>= shift; } - -inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; } -inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; } -inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; } -inline const uint160 operator+(const base_uint160& a, const base_uint160& b) { return uint160(a) += b; } -inline const uint160 operator-(const base_uint160& a, const base_uint160& b) { return uint160(a) -= b; } - -inline bool operator<(const base_uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } -inline bool operator<=(const base_uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } -inline bool operator>(const base_uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } -inline bool operator>=(const base_uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } -inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } -inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } -inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } -inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } -inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } -inline const uint160 operator+(const base_uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } -inline const uint160 operator-(const base_uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } - -inline bool operator<(const uint160& a, const base_uint160& b) { return (base_uint160)a < (base_uint160)b; } -inline bool operator<=(const uint160& a, const base_uint160& b) { return (base_uint160)a <= (base_uint160)b; } -inline bool operator>(const uint160& a, const base_uint160& b) { return (base_uint160)a > (base_uint160)b; } -inline bool operator>=(const uint160& a, const base_uint160& b) { return (base_uint160)a >= (base_uint160)b; } -inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; } -inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; } -inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; } -inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; } -inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; } -inline const uint160 operator+(const uint160& a, const base_uint160& b) { return (base_uint160)a + (base_uint160)b; } -inline const uint160 operator-(const uint160& a, const base_uint160& b) { return (base_uint160)a - (base_uint160)b; } - -inline bool operator<(const uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } -inline bool operator<=(const uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } -inline bool operator>(const uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } -inline bool operator>=(const uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } -inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } -inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } -inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } -inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } -inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } -inline const uint160 operator+(const uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } -inline const uint160 operator-(const uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } - - - -////////////////////////////////////////////////////////////////////////////// -// -// uint256 -// - -/** 256-bit unsigned integer */ -class uint256 : public base_uint256 -{ +/** 256-bit unsigned big integer. */ +class uint256 : public base_uint<256> { public: - typedef base_uint256 basetype; - - uint256() - { - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - } - - uint256(const basetype& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - } - - uint256& operator=(const basetype& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - return *this; - } - - uint256(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - } - - uint256& operator=(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - return *this; - } - - explicit uint256(const std::string& str) - { - SetHex(str); - } - - explicit uint256(const std::vector<unsigned char>& vch) - { - if (vch.size() == sizeof(pn)) - memcpy(pn, &vch[0], sizeof(pn)); - else - *this = 0; - } + uint256() {} + uint256(const base_uint<256>& b) : base_uint<256>(b) {} + uint256(uint64_t b) : base_uint<256>(b) {} + explicit uint256(const std::string& str) : base_uint<256>(str) {} + explicit uint256(const std::vector<unsigned char>& vch) : base_uint<256>(vch) {} + + // The "compact" format is a representation of a whole + // number N using an unsigned 32bit number similar to a + // floating point format. + // The most significant 8 bits are the unsigned exponent of base 256. + // This exponent can be thought of as "number of bytes of N". + // The lower 23 bits are the mantissa. + // Bit number 24 (0x800000) represents the sign of N. + // N = (-1^sign) * mantissa * 256^(exponent-3) + // + // Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). + // MPI uses the most significant bit of the first byte as sign. + // Thus 0x1234560000 is compact (0x05123456) + // and 0xc0de000000 is compact (0x0600c0de) + // (0x05c0de00) would be -0x40de000000 + // + // Bitcoin only uses this "compact" format for encoding difficulty + // targets, which are unsigned 256bit quantities. Thus, all the + // complexities of the sign bit and using base 256 are probably an + // implementation accident. + uint256& SetCompact(uint32_t nCompact, bool *pfNegative = NULL, bool *pfOverflow = NULL); + uint32_t GetCompact(bool fNegative = false) const; }; -inline bool operator==(const uint256& a, uint64_t b) { return (base_uint256)a == b; } -inline bool operator!=(const uint256& a, uint64_t b) { return (base_uint256)a != b; } -inline const uint256 operator<<(const base_uint256& a, unsigned int shift) { return uint256(a) <<= shift; } -inline const uint256 operator>>(const base_uint256& a, unsigned int shift) { return uint256(a) >>= shift; } -inline const uint256 operator<<(const uint256& a, unsigned int shift) { return uint256(a) <<= shift; } -inline const uint256 operator>>(const uint256& a, unsigned int shift) { return uint256(a) >>= shift; } - -inline const uint256 operator^(const base_uint256& a, const base_uint256& b) { return uint256(a) ^= b; } -inline const uint256 operator&(const base_uint256& a, const base_uint256& b) { return uint256(a) &= b; } -inline const uint256 operator|(const base_uint256& a, const base_uint256& b) { return uint256(a) |= b; } -inline const uint256 operator+(const base_uint256& a, const base_uint256& b) { return uint256(a) += b; } -inline const uint256 operator-(const base_uint256& a, const base_uint256& b) { return uint256(a) -= b; } - -inline bool operator<(const base_uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } -inline bool operator<=(const base_uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } -inline bool operator>(const base_uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } -inline bool operator>=(const base_uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } -inline bool operator==(const base_uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } -inline bool operator!=(const base_uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } -inline const uint256 operator^(const base_uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } -inline const uint256 operator&(const base_uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } -inline const uint256 operator|(const base_uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } -inline const uint256 operator+(const base_uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } -inline const uint256 operator-(const base_uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } - -inline bool operator<(const uint256& a, const base_uint256& b) { return (base_uint256)a < (base_uint256)b; } -inline bool operator<=(const uint256& a, const base_uint256& b) { return (base_uint256)a <= (base_uint256)b; } -inline bool operator>(const uint256& a, const base_uint256& b) { return (base_uint256)a > (base_uint256)b; } -inline bool operator>=(const uint256& a, const base_uint256& b) { return (base_uint256)a >= (base_uint256)b; } -inline bool operator==(const uint256& a, const base_uint256& b) { return (base_uint256)a == (base_uint256)b; } -inline bool operator!=(const uint256& a, const base_uint256& b) { return (base_uint256)a != (base_uint256)b; } -inline const uint256 operator^(const uint256& a, const base_uint256& b) { return (base_uint256)a ^ (base_uint256)b; } -inline const uint256 operator&(const uint256& a, const base_uint256& b) { return (base_uint256)a & (base_uint256)b; } -inline const uint256 operator|(const uint256& a, const base_uint256& b) { return (base_uint256)a | (base_uint256)b; } -inline const uint256 operator+(const uint256& a, const base_uint256& b) { return (base_uint256)a + (base_uint256)b; } -inline const uint256 operator-(const uint256& a, const base_uint256& b) { return (base_uint256)a - (base_uint256)b; } - -inline bool operator<(const uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } -inline bool operator<=(const uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } -inline bool operator>(const uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } -inline bool operator>=(const uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } -inline bool operator==(const uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } -inline bool operator!=(const uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } -inline const uint256 operator^(const uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } -inline const uint256 operator&(const uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } -inline const uint256 operator|(const uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } -inline const uint256 operator+(const uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } -inline const uint256 operator-(const uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } - #endif diff --git a/src/util.cpp b/src/util.cpp index a919b4b854..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 } @@ -303,26 +320,6 @@ int LogPrintStr(const std::string &str) return ret; } -void ParseString(const string& str, char c, vector<string>& v) -{ - if (str.empty()) - return; - string::size_type i1 = 0; - string::size_type i2; - while (true) - { - i2 = str.find(c, i1); - if (i2 == str.npos) - { - v.push_back(str.substr(i1)); - return; - } - v.push_back(str.substr(i1, i2-i1)); - i1 = i2+1; - } -} - - string FormatMoney(int64_t n, bool fPlus) { // Note: not using straight sprintf here because we do NOT want @@ -424,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) @@ -479,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]); @@ -494,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); } @@ -504,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); } } @@ -889,43 +887,6 @@ string DecodeBase32(const string& str) return string((const char*)&vchRet[0], vchRet.size()); } - -bool WildcardMatch(const char* psz, const char* mask) -{ - while (true) - { - switch (*mask) - { - case '\0': - return (*psz == '\0'); - case '*': - return WildcardMatch(psz, mask+1) || (*psz && WildcardMatch(psz+1, mask)); - case '?': - if (*psz == '\0') - return false; - break; - default: - if (*psz != *mask) - return false; - break; - } - psz++; - mask++; - } -} - -bool WildcardMatch(const string& str, const string& mask) -{ - return WildcardMatch(str.c_str(), mask.c_str()); -} - - - - - - - - static std::string FormatException(std::exception* pex, const char* pszThread) { #ifdef WIN32 @@ -942,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); @@ -985,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) @@ -994,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]; @@ -1014,7 +969,7 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) path = GetDefaultDataDir(); } if (fNetSpecific) - path /= Params().DataDir(); + path /= BaseParams().DataDir(); fs::create_directories(path); @@ -1023,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; } @@ -1090,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 @@ -1205,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); } } @@ -1221,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() @@ -1242,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) @@ -1427,3 +1308,78 @@ void RenameThread(const char* name) #endif } +bool ParseInt32(const std::string& str, int32_t *out) +{ + char *endp = NULL; + errno = 0; // strtol will not set errno if valid + long int n = strtol(str.c_str(), &endp, 10); + if(out) *out = (int)n; + // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit + // platforms the size of these types may be different. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits<int32_t>::min() && + n <= std::numeric_limits<int32_t>::max(); +} + +void SetupEnvironment() +{ +#ifndef WIN32 + try + { +#if BOOST_FILESYSTEM_VERSION == 3 + boost::filesystem::path::codecvt(); // Raises runtime error if current locale is invalid +#else // boost filesystem v2 + std::locale(); // Raises runtime error if current locale is invalid +#endif + } catch(std::runtime_error &e) + { + setenv("LC_ALL", "C", 1); // Force C locale + } +#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 fbd841f7a8..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; @@ -44,18 +43,6 @@ static const int64_t CENT = 1000000; #define UEND(a) ((unsigned char*)&((&(a))[1])) #define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) -/* Format characters for (s)size_t, ptrdiff_t. - * - * Define these as empty as the tinyformat-based formatting system is - * type-safe, no special format characters are needed to specify sizes. - */ -#define PRIszx "x" -#define PRIszu "u" -#define PRIszd "d" -#define PRIpdx "x" -#define PRIpdu "u" -#define PRIpdd "d" - // This is needed because the foreach macro can't get over the comma in pair<t1, t2> #define PAIRTYPE(t1, t2) std::pair<t1, t2> @@ -112,12 +99,13 @@ 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(); void RandAddSeedPerfmon(); +void SetupEnvironment(); /* Return true if log accepts specified category */ bool LogAcceptCategory(const char* category); @@ -162,16 +150,14 @@ 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); -void ParseString(const std::string& str, char c, std::vector<std::string>& v); std::string FormatMoney(int64_t n, bool fPlus=false); bool ParseMoney(const std::string& str, int64_t& nRet); 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); @@ -182,8 +168,6 @@ std::string DecodeBase32(const std::string& str); std::string EncodeBase32(const unsigned char* pch, size_t len); std::string EncodeBase32(const std::string& str); void ParseParameters(int argc, const char*const argv[]); -bool WildcardMatch(const char* psz, const char* mask); -bool WildcardMatch(const std::string& str, const std::string& mask); void FileCommit(FILE *fileout); bool TruncateFile(FILE *file, unsigned int length); int RaiseFileDescriptorLimit(int nMinFD); @@ -208,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); @@ -256,6 +237,13 @@ inline int atoi(const std::string& str) return atoi(str.c_str()); } +/** + * Convert string to signed 32-bit integer with strict parse error feedback. + * @returns true if the entire string could be parsed as valid integer, + * false if not the entire string could be parsed or when overflow or underflow occured. + */ +bool ParseInt32(const std::string& str, int32_t *out); + inline int roundint(double d) { return (int)(d > 0 ? d + 0.5 : d - 0.5); @@ -296,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() { @@ -332,21 +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; -} - -template<typename T> -void skipspaces(T& it) -{ - while (isspace(*it)) - ++it; -} +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 418720de93..ea99b89a5a 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 (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")) @@ -1638,7 +1770,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) throw runtime_error("TopUpKeyPool() : writing generated key failed"); setKeyPool.insert(nEnd); - LogPrintf("keypool added key %d, size=%"PRIszu"\n", nEnd, setKeyPool.size()); + LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size()); } } return true; @@ -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 359a1cef61..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; @@ -894,7 +917,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename); return false; } - LogPrintf("Salvage(aggressive) found %"PRIszu" records\n", salvagedData.size()); + LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size()); bool fSuccess = allOK; Db* pdbCopy = new Db(&dbenv.dbenv, 0); 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); }; |