diff options
150 files changed, 3277 insertions, 1719 deletions
diff --git a/.gitignore b/.gitignore index e21ea92552..24af4cb72e 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,8 @@ src/m4/ltsugar.m4 src/m4/ltversion.m4 src/m4/lt~obsolete.m4 +src/univalue/gen + src/qt/*.moc src/qt/moc_*.cpp src/qt/forms/ui_*.h @@ -41,6 +43,7 @@ src/qt/test/moc*.cpp *.bak *.rej *.orig +*.pyc *.o *.o-* *.patch diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..2073e71769 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,57 @@ +# errata: +# - A travis bug causes caches to trample eachother when using the same +# compiler key (which we don't use anyway). This is worked around for now by +# using the phony compilers "true X". These can be removed when the travis +# bug is fixed. See: https://github.com/travis-ci/casher/issues/6 + +os: linux +language: cpp +env: + global: + - MAKEJOBS=-j3 + - RUN_TESTS=false + - CCACHE_SIZE=100M + - CCACHE_TEMPDIR=/tmp/.ccache-temp + - CCACHE_COMPRESS=1 + - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out +cache: + apt: true + directories: + - depends/built + - $HOME/.ccache +matrix: + fast_finish: true + include: + - compiler: "true 1" + env: HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf" DEP_OPTS="NO_QT=1" GOAL="install" BITCOIN_CONFIG"--enable-glibc-back-compat" + - compiler: "true 2" + env: HOST=x86_64-unknown-linux-gnu DEP_OPTS="NO_QT=1 NO_WALLET=1 NO_UPNP=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat" + - compiler: "true 3" + env: HOST=x86_64-unknown-linux-gnu RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat" + - compiler: "true 4" + env: HOST=i686-pc-linux-gnu PACKAGES="g++-multilib" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat" + - compiler: "true 6" + env: HOST=x86_64-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev" GOAL="deploy" + - compiler: "true 7" + env: HOST=i686-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev" GOAL="deploy" +install: + - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi + - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-upgrade -qq $PACKAGES; fi +before_script: + - unset CC; unset CXX + - mkdir -p depends/SDKs + - make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS || (echo "Build failure. Verbose build follows." && make -C depends V=1 HOST=$HOST $DEP_OPTS) +script: + - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST + - BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" + - depends/$HOST/native/bin/ccache --max-size=$CCACHE_SIZE + - if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then export CCACHE_READONLY=1; fi + - ./autogen.sh + - ./configure --cache-file=config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) + - make distdir PACKAGE=bitcoin VERSION=$HOST + - cd bitcoin-$HOST + - ./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) + - make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false ) + - if [ "$RUN_TESTS" = "true" ]; then make check; fi +after_script: + - if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then (echo "Upload goes here. Something like: scp -r $BASE_OUTDIR server" || echo "upload failed"); fi @@ -1,6 +1,8 @@ Bitcoin Core integration/staging tree ===================================== +[![Build Status](https://travis-ci.org/bitcoin/bitcoin.svg?branch=master)](https://travis-ci.org/bitcoin/bitcoin) + https://www.bitcoin.org Copyright (c) 2009-2014 Bitcoin Core Developers diff --git a/configure.ac b/configure.ac index 55fc091bc5..5a2d7e8e41 100644 --- a/configure.ac +++ b/configure.ac @@ -90,6 +90,12 @@ AC_ARG_ENABLE([hardening], [use_hardening=$enableval], [use_hardening=yes]) +AC_ARG_ENABLE([reduce-exports], + [AS_HELP_STRING([--enable-reduce-exports], + [attempt to reduce exported symbols in the resulting executables (default is yes)])], + [use_reduce_exports=$enableval], + [use_reduce_exports=auto]) + AC_ARG_ENABLE([ccache], [AS_HELP_STRING([--enable-ccache], [use ccache for building (default is yes if ccache is found)])], @@ -304,7 +310,6 @@ AC_C_BIGENDIAN([AC_MSG_ERROR("Big Endian not supported")]) dnl Check for pthread compile/link requirements AX_PTHREAD -INCLUDES="$INCLUDES $PTHREAD_CFLAGS" # The following macro will add the necessary defines to bitcoin-config.h, but # they also need to be passed down to any subprojects. Pull the results out of @@ -397,6 +402,36 @@ AC_TRY_COMPILE([#include <sys/socket.h>], AC_SEARCH_LIBS([clock_gettime],[rt]) +AC_MSG_CHECKING([for visibility attribute]) +AC_LINK_IFELSE([AC_LANG_SOURCE([ + int foo_def( void ) __attribute__((visibility("default"))); + int main(){} + ])], + [ + AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE,1,[Define if the visibility attribute is supported.]) + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_RESULT(no) + if test x$use_reduce_exports = xyes; then + AC_MSG_ERROR([Cannot find a working visibility attribute. Use --disable-reduced-exports.]) + fi + AC_MSG_WARN([Cannot find a working visibility attribute. Disabling reduced exports.]) + use_reduce_exports=no + ] +) + +if test x$use_reduce_exports != xno; then + AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[RE_CXXFLAGS="-fvisibility=hidden"], + [ + if test x$use_reduce_exports = xyes; then + AC_MSG_ERROR([Cannot set default symbol visibility. Use --disable-reduced-exports.]) + fi + AC_MSG_WARN([Cannot set default symbol visibility. Disabling reduced exports.]) + use_reduce_exports=no + ]) +fi + LEVELDB_CPPFLAGS= LIBLEVELDB= LIBMEMENV= @@ -427,6 +462,40 @@ AX_BOOST_PROGRAM_OPTIONS AX_BOOST_THREAD AX_BOOST_CHRONO + +if test x$use_reduce_exports != xno; then + AC_MSG_CHECKING([for working boost reduced exports]) + TEMP_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$BOOST_CPPFLAGS $CPPFLAGS" + AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[ + @%:@include <boost/version.hpp> + ]], [[ + #if BOOST_VERSION >= 104900 + // Everything is okay + #else + # error Boost version is too old + #endif + ]])],[ + AC_MSG_RESULT(yes) + ],[: + if test x$use_reduce_exports = xauto; then + use_reduce_exports=no + else + if test x$use_reduce_exports = xyes; then + AC_MSG_ERROR([boost versions < 1.49 are known to be broken with reduced exports. Use --disable-reduced-exports.]) + fi + fi + AC_MSG_RESULT(no) + AC_MSG_WARN([boost versions < 1.49 are known to have symbol visibility issues. Disabling reduced exports.]) + ]) + CPPFLAGS="$TEMP_CPPFLAGS" +fi + +if test x$use_reduce_exports != xno; then + CXXFLAGS="$CXXFLAGS $RE_CXXFLAGS" + AX_CHECK_LINK_FLAG([[-Wl,--exclude-libs,ALL]], [RELDFLAGS="-Wl,--exclude-libs,ALL"]) +fi + if test x$use_tests = xyes; then if test x$HEXDUMP = x; then @@ -456,7 +525,6 @@ if test x$use_tests = xyes; then fi BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB" -BOOST_INCLUDES="$BOOST_CPPFLAGS" dnl Boost >= 1.50 uses sleep_for rather than the now-deprecated sleep, however dnl it was broken from 1.50 to 1.52 when backed by nanosleep. Use sleep_for if @@ -509,18 +577,18 @@ CPPFLAGS="$TEMP_CPPFLAGS" fi if test x$boost_sleep != xyes; then - AC_MSG_ERROR(No working boost sleep implementation found. If on ubuntu 13.10 with libboost1.54-all-dev remove libboost.1.54-all-dev and use libboost1.53-all-dev) + AC_MSG_ERROR(No working boost sleep implementation found.) fi -AC_ARG_WITH([cli], - [AS_HELP_STRING([--with-cli], - [with CLI (default is yes)])], - [build_bitcoin_cli=$withval], - [build_bitcoin_cli=yes]) +AC_ARG_WITH([utils], + [AS_HELP_STRING([--with-utils], + [build bitcoin-cli bitcoin-tx (default=yes)])], + [build_bitcoin_utils=$withval], + [build_bitcoin_utils=yes]) AC_ARG_WITH([daemon], [AS_HELP_STRING([--with-daemon], - [with daemon (default is yes)])], + [build bitcoind daemon (default=yes)])], [build_bitcoind=$withval], [build_bitcoind=yes]) @@ -536,8 +604,8 @@ if test x$use_pkgconfig = xyes; then m4_ifdef( [PKG_CHECK_MODULES], [ - PKG_CHECK_MODULES([SSL], [libssl], [INCLUDES="$INCLUDES $SSL_CFLAGS"; LIBS="$LIBS $SSL_LIBS"], [AC_MSG_ERROR(openssl not found.)]) - PKG_CHECK_MODULES([CRYPTO], [libcrypto], [INCLUDES="$INCLUDES $CRYPTO_CFLAGS"; LIBS="$LIBS $CRYPTO_LIBS"], [AC_MSG_ERROR(libcrypto not found.)]) + PKG_CHECK_MODULES([SSL], [libssl],, [AC_MSG_ERROR(openssl not found.)]) + PKG_CHECK_MODULES([CRYPTO], [libcrypto],,[AC_MSG_ERROR(libcrypto not found.)]) BITCOIN_QT_CHECK([PKG_CHECK_MODULES([PROTOBUF], [protobuf], [have_protobuf=yes], [BITCOIN_QT_FAIL(libprotobuf not found)])]) if test x$use_qr != xno; then BITCOIN_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])]) @@ -546,10 +614,10 @@ if test x$use_pkgconfig = xyes; then ) else AC_CHECK_HEADER([openssl/crypto.h],,AC_MSG_ERROR(libcrypto headers missing)) - AC_CHECK_LIB([crypto], [main],, AC_MSG_ERROR(libcrypto missing)) + AC_CHECK_LIB([crypto], [main],CRYPTO_LIBS=-lcrypto, AC_MSG_ERROR(libcrypto missing)) AC_CHECK_HEADER([openssl/ssl.h],, AC_MSG_ERROR(libssl headers missing),) - AC_CHECK_LIB([ssl], [main],, AC_MSG_ERROR(libssl missing)) + AC_CHECK_LIB([ssl], [main],SSL_LIBS=-lssl, AC_MSG_ERROR(libssl missing)) BITCOIN_QT_CHECK(AC_CHECK_LIB([protobuf] ,[main],,BITCOIN_QT_FAIL(libprotobuf not found))) if test x$use_qr != xno; then @@ -564,9 +632,9 @@ AC_MSG_CHECKING([whether to build bitcoind]) AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes]) AC_MSG_RESULT($build_bitcoind) -AC_MSG_CHECKING([whether to build bitcoin-cli]) -AM_CONDITIONAL([BUILD_BITCOIN_CLI], [test x$build_bitcoin_cli = xyes]) -AC_MSG_RESULT($build_bitcoin_cli) +AC_MSG_CHECKING([whether to build utils (bitcoin-cli bitcoin-tx)]) +AM_CONDITIONAL([BUILD_BITCOIN_UTILS], [test x$build_bitcoin_utils = xyes]) +AC_MSG_RESULT($build_bitcoin_utils) dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus BITCOIN_QT_CONFIGURE([$use_pkgconfig], [qt4]) @@ -588,6 +656,9 @@ if test "x$use_ccache" != "xno"; then fi AC_MSG_RESULT($use_ccache) fi +if test "x$use_ccache" = "xyes"; then + AX_CHECK_PREPROC_FLAG([-Qunused-arguments],[CPPFLAGS="-Qunused-arguments $CPPFLAGS"]) +fi dnl enable wallet AC_MSG_CHECKING([if wallet should be enabled]) @@ -674,8 +745,15 @@ else AC_MSG_RESULT([no]) fi -if test "x$use_tests$build_bitcoind$use_qt" = "xnonono"; then - AC_MSG_ERROR([No targets! Please specify at least one of: --enable-cli --enable-daemon --enable-gui or --enable-tests]) +AC_MSG_CHECKING([whether to reduce exports]) +if test x$use_reduce_exports != xno; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests = xnononono; then + AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-daemon --with-gui or --enable-tests]) fi AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) @@ -706,10 +784,10 @@ AC_SUBST(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE) AC_SUBST(COPYRIGHT_YEAR, _COPYRIGHT_YEAR) +AC_SUBST(RELDFLAGS) AC_SUBST(LIBTOOL_LDFLAGS) AC_SUBST(USE_UPNP) AC_SUBST(USE_QRCODE) -AC_SUBST(INCLUDES) AC_SUBST(BOOST_LIBS) AC_SUBST(TESTDEFS) AC_SUBST(LEVELDB_TARGET_FLAGS) diff --git a/contrib/devtools/github-merge.sh b/contrib/devtools/github-merge.sh index e42b71a54a..3217a06195 100755 --- a/contrib/devtools/github-merge.sh +++ b/contrib/devtools/github-merge.sh @@ -49,11 +49,11 @@ fi # Initialize source branches. git checkout -q "$BRANCH" if git fetch -q "$HOST":"$REPO" "+refs/pull/$PULL/*:refs/heads/pull/$PULL/*"; then - if ! git log -1q "refs/heads/pull/$PULL/head" >/dev/null 2>&1; then + if ! git log -q -1 "refs/heads/pull/$PULL/head" >/dev/null 2>&1; then echo "ERROR: Cannot find head of pull request #$PULL on $HOST:$REPO." >&2 exit 3 fi - if ! git log -1q "refs/heads/pull/$PULL/merge" >/dev/null 2>&1; then + if ! git log -q -1 "refs/heads/pull/$PULL/merge" >/dev/null 2>&1; then echo "ERROR: Cannot find merge of pull request #$PULL on $HOST:$REPO." >&2 exit 3 fi diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index 8dd6d8f037..f3999f1c0b 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -41,6 +41,10 @@ MAX_VERSIONS = { 'GLIBCXX': (3,4,13), 'GLIBC': (2,11) } +# Ignore symbols that are exported as part of every executable +IGNORE_EXPORTS = { +'_edata', '_end', '_init', '__bss_start', '_fini' +} READELF_CMD = '/usr/bin/readelf' CPPFILT_CMD = '/usr/bin/c++filt' @@ -105,6 +109,8 @@ if __name__ == '__main__': retval = 1 # Check exported symbols for sym,version in read_symbols(filename, False): + if sym in IGNORE_EXPORTS: + continue print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym))) retval = 1 diff --git a/contrib/linearize/README.md b/contrib/linearize/README.md index 70b9f034cd..b5c6e7824e 100644 --- a/contrib/linearize/README.md +++ b/contrib/linearize/README.md @@ -1,2 +1,32 @@ -### Linearize ### -Construct a linear, no-fork, best version of the blockchain.
\ No newline at end of file +# Linearize +Construct a linear, no-fork, best version of the blockchain. + +## Step 1: Download hash list + + $ ./linearize-hashes.py linearize.cfg > hashlist.txt + +Required configuration file settings for linearize-hashes: +* RPC: rpcuser, rpcpassword + +Optional config file setting for linearize-hashes: +* RPC: host, port +* Block chain: min_height, max_height + +## Step 2: Copy local block data + + $ ./linearize-data.py linearize.cfg + +Required configuration file settings: +* "input": bitcoind blocks/ directory containing blkNNNNN.dat +* "hashlist": text file containing list of block hashes, linearized-hashes.py +output. +* "output_file": bootstrap.dat + or +* "output": output directory for linearized blocks/blkNNNNN.dat output + +Optional config file setting for linearize-data: +* "netmagic": network magic number +* "max_out_sz": maximum output file size (default 1000*1000*1000) +* "split_year": Split files when a new year is first seen, in addition to +reaching a maximum file size. + diff --git a/contrib/linearize/example-linearize.cfg b/contrib/linearize/example-linearize.cfg index f5cdab5325..071345f23a 100644 --- a/contrib/linearize/example-linearize.cfg +++ b/contrib/linearize/example-linearize.cfg @@ -1,12 +1,17 @@ -# bitcoind RPC settings +# bitcoind RPC settings (linearize-hashes) rpcuser=someuser rpcpassword=somepassword host=127.0.0.1 port=8332 -# bootstrap.dat settings +# bootstrap.dat hashlist settings (linearize-hashes) +max_height=313000 + +# bootstrap.dat input/output settings (linearize-data) netmagic=f9beb4d9 -max_height=279000 -output=bootstrap.dat +input=/home/example/.bitcoin/blocks +output_file=/home/example/Downloads/bootstrap.dat +hashlist=hashlist.txt +split_year=1 diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py new file mode 100755 index 0000000000..ea94f25fae --- /dev/null +++ b/contrib/linearize/linearize-data.py @@ -0,0 +1,208 @@ +#!/usr/bin/python +# +# linearize-data.py: Construct a linear, no-fork version of the chain. +# +# Copyright (c) 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. +# + +import json +import struct +import re +import base64 +import httplib +import sys +import hashlib +import datetime + +settings = {} + + +def uint32(x): + return x & 0xffffffffL + +def bytereverse(x): + return uint32(( ((x) << 24) | (((x) << 8) & 0x00ff0000) | + (((x) >> 8) & 0x0000ff00) | ((x) >> 24) )) + +def bufreverse(in_buf): + out_words = [] + for i in range(0, len(in_buf), 4): + word = struct.unpack('@I', in_buf[i:i+4])[0] + out_words.append(struct.pack('@I', bytereverse(word))) + return ''.join(out_words) + +def wordreverse(in_buf): + out_words = [] + for i in range(0, len(in_buf), 4): + out_words.append(in_buf[i:i+4]) + out_words.reverse() + return ''.join(out_words) + +def calc_hdr_hash(blk_hdr): + hash1 = hashlib.sha256() + hash1.update(blk_hdr) + hash1_o = hash1.digest() + + hash2 = hashlib.sha256() + hash2.update(hash1_o) + hash2_o = hash2.digest() + + return hash2_o + +def calc_hash_str(blk_hdr): + hash = calc_hdr_hash(blk_hdr) + hash = bufreverse(hash) + hash = wordreverse(hash) + hash_str = hash.encode('hex') + return hash_str + +def get_blk_year(blk_hdr): + members = struct.unpack("<I", blk_hdr[68:68+4]) + dt = datetime.datetime.fromtimestamp(members[0]) + return dt.year + +def get_block_hashes(settings): + blkindex = [] + f = open(settings['hashlist'], "r") + for line in f: + line = line.rstrip() + blkindex.append(line) + + print("Read " + str(len(blkindex)) + " hashes") + + return blkindex + +def mkblockset(blkindex): + blkmap = {} + for hash in blkindex: + blkmap[hash] = True + return blkmap + +def copydata(settings, blkindex, blkset): + inFn = 0 + inF = None + outFn = 0 + outsz = 0 + outF = None + blkCount = 0 + + lastYear = 0 + splitYear = False + fileOutput = True + maxOutSz = settings['max_out_sz'] + if 'output' in settings: + fileOutput = False + if settings['split_year'] != 0: + splitYear = True + + while True: + if not inF: + fname = "%s/blk%05d.dat" % (settings['input'], inFn) + print("Input file" + fname) + inF = open(fname, "rb") + + inhdr = inF.read(8) + if (not inhdr or (inhdr[0] == "\0")): + inF.close() + inF = None + inFn = inFn + 1 + continue + + inMagic = inhdr[:4] + if (inMagic != settings['netmagic']): + print("Invalid magic:" + inMagic) + return + inLenLE = inhdr[4:] + su = struct.unpack("<I", inLenLE) + inLen = su[0] + rawblock = inF.read(inLen) + blk_hdr = rawblock[:80] + + hash_str = calc_hash_str(blk_hdr) + if not hash_str in blkset: + print("Skipping unknown block " + hash_str) + continue + + if not fileOutput and ((outsz + inLen) > maxOutSz): + outF.close() + outF = None + outFn = outFn + 1 + outsz = 0 + + if splitYear: + blkYear = get_blk_year(blk_hdr) + if blkYear > lastYear: + print("New year " + str(blkYear) + " @ " + hash_str) + lastYear = blkYear + if outF: + outF.close() + outF = None + outFn = outFn + 1 + outsz = 0 + + if not outF: + if fileOutput: + fname = settings['output_file'] + else: + fname = "%s/blk%05d.dat" % (settings['output'], outFn) + print("Output file" + fname) + outF = open(fname, "wb") + + outF.write(inhdr) + outF.write(rawblock) + outsz = outsz + inLen + 8 + + blkCount = blkCount + 1 + + if (blkCount % 1000) == 0: + print("Wrote " + str(blkCount) + " blocks") + +if __name__ == '__main__': + if len(sys.argv) != 2: + print "Usage: linearize-data.py CONFIG-FILE" + sys.exit(1) + + f = open(sys.argv[1]) + for line in f: + # skip comment lines + m = re.search('^\s*#', line) + if m: + continue + + # parse key=value lines + m = re.search('^(\w+)\s*=\s*(\S.*)$', line) + if m is None: + continue + settings[m.group(1)] = m.group(2) + f.close() + + if 'netmagic' not in settings: + settings['netmagic'] = 'f9beb4d9' + if 'input' not in settings: + settings['input'] = 'input' + if 'hashlist' not in settings: + settings['hashlist'] = 'hashlist.txt' + if 'split_year' not in settings: + settings['split_year'] = 0 + if 'max_out_sz' not in settings: + settings['max_out_sz'] = 1000L * 1000 * 1000 + + settings['max_out_sz'] = long(settings['max_out_sz']) + settings['split_year'] = int(settings['split_year']) + settings['netmagic'] = settings['netmagic'].decode('hex') + + if 'output_file' not in settings and 'output' not in settings: + print("Missing output file / directory") + sys.exit(1) + + blkindex = get_block_hashes(settings) + blkset = mkblockset(blkindex) + + if not "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" in blkset: + print("not found") + else: + copydata(settings, blkindex, blkset) + + diff --git a/contrib/linearize/linearize.py b/contrib/linearize/linearize-hashes.py index 650f7d3684..791b71bc33 100644..100755 --- a/contrib/linearize/linearize.py +++ b/contrib/linearize/linearize-hashes.py @@ -1,7 +1,6 @@ #!/usr/bin/python # -# linearize.py: Construct a linear, no-fork, best version of the blockchain. -# +# linearize-hashes.py: List blocks in a linear, no-fork version of the chain. # # Copyright (c) 2013 The Bitcoin developers # Distributed under the MIT/X11 software license, see the accompanying @@ -15,9 +14,6 @@ import base64 import httplib import sys -ERR_SLEEP = 15 -MAX_NONCE = 1000000L - settings = {} class BitcoinRPC: @@ -62,34 +58,18 @@ class BitcoinRPC: def getblockhash(self, index): return self.rpc('getblockhash', [index]) -def getblock(rpc, settings, n): - hash = rpc.getblockhash(n) - hexdata = rpc.getblock(hash, False) - data = hexdata.decode('hex') - - return data - -def get_blocks(settings): +def get_block_hashes(settings): rpc = BitcoinRPC(settings['host'], settings['port'], settings['rpcuser'], settings['rpcpassword']) - outf = open(settings['output'], 'ab') - for height in xrange(settings['min_height'], settings['max_height']+1): - data = getblock(rpc, settings, height) - - outhdr = settings['netmagic'] - outhdr += struct.pack("<i", len(data)) + hash = rpc.getblockhash(height) - outf.write(outhdr) - outf.write(data) - - if (height % 1000) == 0: - sys.stdout.write("Wrote block " + str(height) + "\n") + print(hash) if __name__ == '__main__': if len(sys.argv) != 2: - print "Usage: linearize.py CONFIG-FILE" + print "Usage: linearize-hashes.py CONFIG-FILE" sys.exit(1) f = open(sys.argv[1]) @@ -106,10 +86,6 @@ if __name__ == '__main__': settings[m.group(1)] = m.group(2) f.close() - if 'netmagic' not in settings: - settings['netmagic'] = 'f9beb4d9' - if 'output' not in settings: - settings['output'] = 'bootstrap.dat' if 'host' not in settings: settings['host'] = '127.0.0.1' if 'port' not in settings: @@ -117,16 +93,14 @@ if __name__ == '__main__': if 'min_height' not in settings: settings['min_height'] = 0 if 'max_height' not in settings: - settings['max_height'] = 279000 + settings['max_height'] = 313000 if 'rpcuser' not in settings or 'rpcpassword' not in settings: print "Missing username and/or password in cfg file" sys.exit(1) - settings['netmagic'] = settings['netmagic'].decode('hex') settings['port'] = int(settings['port']) settings['min_height'] = int(settings['min_height']) settings['max_height'] = int(settings['max_height']) - get_blocks(settings) - + get_block_hashes(settings) diff --git a/depends/Makefile b/depends/Makefile index d431653068..f5fb5b865f 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -6,12 +6,15 @@ SDK_PATH ?= $(BASEDIR)/SDKs NO_QT ?= NO_WALLET ?= NO_UPNP ?= +FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources BUILD = $(shell ./config.guess) HOST ?= $(BUILD) PATCHES_PATH = $(BASEDIR)/patches BASEDIR = $(CURDIR) HASH_LENGTH:=11 +DOWNLOAD_CONNECT_TIMEOUT:=10 +DOWNLOAD_RETRIES:=3 host:=$(BUILD) ifneq ($(HOST),) @@ -72,7 +75,7 @@ packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_pack native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages) $(qt_native_packages_) all_packages = $(packages) $(native_packages) -meta_depends = Makefile builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk +meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk $(host_arch)_$(host_os)_native_toolchain?=$($(host_os)_native_toolchain) diff --git a/depends/README.usage b/depends/README.usage index f50714f1f1..0aacefbf94 100644 --- a/depends/README.usage +++ b/depends/README.usage @@ -18,6 +18,7 @@ The following can be set when running make: make FOO=bar SOURCES_PATH: downloaded sources will be placed here BASE_CACHE: built packages will be placed here SDK_PATH: Path where sdk's can be found (used by OSX) +FALLBACK_DOWNLOAD_PATH: If a source file can't be fetched, try here before giving up NO_QT: Don't download/build/cache qt and its dependencies NO_WALLET: Don't download/build/cache libs needed to enable the wallet NO_UPNP: Don't download/build/cache packages needed for enabling upnp diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index 6b734648f0..b366460e64 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -7,7 +7,7 @@ build_darwin_OTOOL: = $(shell xcrun -f otool) build_darwin_NM: = $(shell xcrun -f nm) build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) build_darwin_SHA256SUM = shasum -a 256 -build_darwin_DOWNLOAD = curl -L -o +build_darwin_DOWNLOAD = curl --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -o #darwin host on darwin builder. overrides darwin host preferences. darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) diff --git a/depends/builders/linux.mk b/depends/builders/linux.mk index d98ba597dc..98d0e9de34 100644 --- a/depends/builders/linux.mk +++ b/depends/builders/linux.mk @@ -1,2 +1,2 @@ build_linux_SHA256SUM = sha256sum -build_linux_DOWNLOAD = wget -nv -O +build_linux_DOWNLOAD = wget --timeout=$(DOWNLOAD_CONNECT_TIMEOUT) --tries=$(DOWNLOAD_RETRIES) -nv -O diff --git a/depends/funcs.mk b/depends/funcs.mk index 4c47cc926e..280706efb3 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -20,7 +20,13 @@ $(sort $(foreach dep,$(2),$(2) $(call int_get_all_dependencies,$(1),$($(dep)_dep endef define fetch_file -(test -f $(SOURCES_PATH)/$(3) || ( mkdir -p $$($(1)_extract_dir) && $(build_DOWNLOAD) "$$($(1)_extract_dir)/$(3).temp" "$(2)" && echo "$(4) $$($(1)_extract_dir)/$(3).temp" | $(build_SHA256SUM) -c && mv $$($(1)_extract_dir)/$(3).temp $(SOURCES_PATH)/$(3) )) +(test -f $(SOURCES_PATH)/$(4) || \ + ( mkdir -p $$($(1)_extract_dir) && \ + ( $(build_DOWNLOAD) "$$($(1)_extract_dir)/$(3).temp" "$(2)/$(3)" || \ + $(build_DOWNLOAD) "$$($(1)_extract_dir)/$(3).temp" "$(FALLBACK_DOWNLOAD_PATH)/$(3)" ) && \ + echo "$(5) $$($(1)_extract_dir)/$(4).temp" > $$($(1)_extract_dir)/.$(4).hash && \ + $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$(4).hash && \ + mv $$($(1)_extract_dir)/$(4).temp $(SOURCES_PATH)/$(4) )) endef define int_get_build_recipe_hash @@ -61,8 +67,8 @@ $(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path)) #default commands -$(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)/$$($(1)_download_file)),$($(1)_file_name),$($(1)_sha256_hash)) -$(1)_extract_cmds ?= echo "$$($(1)_sha256_hash) $$($(1)_source)" | $(build_SHA256SUM) -c && tar --strip-components=1 -xf $$($(1)_source) +$(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash)) +$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --strip-components=1 -xf $$($(1)_source) $(1)_preprocess_cmds ?= $(1)_build_cmds ?= $(1)_config_cmds ?= diff --git a/depends/packages/native_cctools.mk b/depends/packages/native_cctools.mk index e3ba9685b4..ad989cb544 100644 --- a/depends/packages/native_cctools.mk +++ b/depends/packages/native_cctools.mk @@ -23,11 +23,11 @@ $(package)_clang_file_name=clang-llvm-3.2-x86-linux-ubuntu-12.04.tar.gz $(package)_clang_sha256_hash=b9d57a88f9514fa1f327a1a703756d0c1c960f4c58494a5bd80313245d13ffff define $(package)_fetch_cmds -$(call fetch_file,$(package),$($(package)_download_path)/$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ -$(call fetch_file,$(package),$($(package)_ld64_download_path)/$($(package)_ld64_download_file),$($(package)_ld64_file_name),$($(package)_ld64_sha256_hash)) && \ -$(call fetch_file,$(package),$($(package)_dyld_download_path)/$($(package)_dyld_download_file),$($(package)_dyld_file_name),$($(package)_dyld_sha256_hash)) && \ -$(call fetch_file,$(package),$($(package)_clang_download_path)/$($(package)_clang_download_file),$($(package)_clang_file_name),$($(package)_clang_sha256_hash)) && \ -$(call fetch_file,$(package),$($(package)_toolchain4_download_path)/$($(package)_toolchain4_download_file),$($(package)_toolchain4_file_name),$($(package)_toolchain4_sha256_hash)) +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_ld64_download_path),$($(package)_ld64_download_file),$($(package)_ld64_file_name),$($(package)_ld64_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_dyld_download_path),$($(package)_dyld_download_file),$($(package)_dyld_file_name),$($(package)_dyld_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_clang_download_path),$($(package)_clang_download_file),$($(package)_clang_file_name),$($(package)_clang_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_toolchain4_download_path),$($(package)_toolchain4_download_file),$($(package)_toolchain4_file_name),$($(package)_toolchain4_sha256_hash)) endef define $(package)_set_vars diff --git a/depends/packages/native_comparisontool.mk b/depends/packages/native_comparisontool.mk index 5eef73052f..003923d7dd 100644 --- a/depends/packages/native_comparisontool.mk +++ b/depends/packages/native_comparisontool.mk @@ -15,12 +15,12 @@ $(package)_slf4j-jdk14_file_name=slf4j-jdk14-1.6.4.jar $(package)_slf4j-jdk14_sha256_hash=064bd81796710f713f9f4a2309c0e032309934c2d2b4f7d3b6958325e584e13f define $(package)_fetch_cmds -$(call fetch_file,$(package),$($(package)_download_path)/$($(package)_file_name),$($(package)_file_name),$($(package)_sha256_hash)) && \ -$(call fetch_file,$(package),$($(package)_download_path)/$($(package)_guava_file_name),$($(package)_guava_file_name),$($(package)_guava_sha256_hash)) && \ -$(call fetch_file,$(package),$($(package)_download_path)/$($(package)_h2_file_name),$($(package)_h2_file_name),$($(package)_h2_sha256_hash)) && \ -$(call fetch_file,$(package),$($(package)_download_path)/$($(package)_sc-light-jdk15on_file_name),$($(package)_sc-light-jdk15on_file_name),$($(package)_sc-light-jdk15on_sha256_hash)) && \ -$(call fetch_file,$(package),$($(package)_download_path)/$($(package)_slf4j-api_file_name),$($(package)_slf4j-api_file_name),$($(package)_slf4j-api_sha256_hash)) && \ -$(call fetch_file,$(package),$($(package)_download_path)/$($(package)_slf4j-jdk14_file_name),$($(package)_slf4j-jdk14_file_name),$($(package)_slf4j-jdk14_sha256_hash)) +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_file_name),$($(package)_file_name),$($(package)_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_guava_file_name),$($(package)_guava_file_name),$($(package)_guava_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_h2_file_name),$($(package)_h2_file_name),$($(package)_h2_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_sc-light-jdk15on_file_name),$($(package)_sc-light-jdk15on_file_name),$($(package)_sc-light-jdk15on_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_slf4j-api_file_name),$($(package)_slf4j-api_file_name),$($(package)_slf4j-api_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_slf4j-jdk14_file_name),$($(package)_slf4j-jdk14_file_name),$($(package)_slf4j-jdk14_sha256_hash)) endef define $(package)_extract_cmds diff --git a/doc/README.md b/doc/README.md index f8bb8020d4..10c9ad1799 100644 --- a/doc/README.md +++ b/doc/README.md @@ -46,7 +46,6 @@ The following are developer notes on how to build Bitcoin on your native platfor - [OSX Build Notes](build-osx.md) - [Unix Build Notes](build-unix.md) -- [Windows Build Notes](build-msw.md) Development --------------------- diff --git a/doc/build-osx.md b/doc/build-osx.md index bc42723b12..ade9eb466b 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -69,21 +69,30 @@ Instructions: Homebrew #### Install dependencies using Homebrew - brew install autoconf automake libtool berkeley-db4 boost miniupnpc openssl pkg-config protobuf qt + brew install autoconf automake libtool 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 +#### Installing berkeley-db4 using Homebrew - openssl version +The homebrew package for berkeley-db4 has been broken for some time. It will install without Java though. -into Terminal. You should see OpenSSL 1.0.1h 5 Jun 2014. +Running this command takes you into brew's interactive mode, which allows you to configure, make, and install by hand: +``` +$ brew install https://raw.github.com/mxcl/homebrew/master/Library/Formula/berkeley-db4.rb -–without-java +``` -If not, you can ensure that the Homebrew OpenSSL is correctly linked by running +These rest of these commands are run inside brew interactive mode: +``` +/private/tmp/berkeley-db4-UGpd0O/db-4.8.30 $ cd .. +/private/tmp/berkeley-db4-UGpd0O $ db-4.8.30/dist/configure --prefix=/usr/local/Cellar/berkeley-db4/4.8.30 --mandir=/usr/local/Cellar/berkeley-db4/4.8.30/share/man --enable-cxx +/private/tmp/berkeley-db4-UGpd0O $ make +/private/tmp/berkeley-db4-UGpd0O $ make install +/private/tmp/berkeley-db4-UGpd0O $ exit +``` - brew link openssl --force +After exiting, you'll get a warning that the install is keg-only, which means it wasn't symlinked to `/usr/local`. You don't need it to link it to build bitcoin, but if you want to, here's how: + + $ brew --force link berkeley-db4 -Rerunning "openssl version" should now return the correct version. If it -doesn't, make sure `/usr/local/bin` comes before `/usr/bin` in your -PATH. ### Building `bitcoind` diff --git a/doc/build-unix.md b/doc/build-unix.md index 0f381d56c5..8a76a8b2cd 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -76,10 +76,6 @@ for Ubuntu 12.04 and later: Ubuntu 12.04 and later have packages for libdb5.1-dev and libdb5.1++-dev, but using these will break binary wallet compatibility, and is not recommended. -for Ubuntu 13.10: - libboost1.54 will not work, - remove libboost1.54-all-dev and install libboost1.53-all-dev instead. - for Debian 7 (Wheezy) and later: The oldstable repository contains db4.8 packages. Add the following line to /etc/apt/sources.list, @@ -113,7 +109,7 @@ To build with Qt 4 you need the following: For Qt 5 you need the following: - sudo apt-get install libqt5gui5 libqt5core5 libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev + sudo apt-get install libqt5gui5 libqt5core5 libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler libqrencode (optional) can be installed with: diff --git a/doc/travis-ci.txt b/doc/travis-ci.txt new file mode 100644 index 0000000000..01f7d02a86 --- /dev/null +++ b/doc/travis-ci.txt @@ -0,0 +1,39 @@ +Support for using travis-ci has been added in order to automate pull-testing. +See https://travis-ci.org/ for more info + +This procedure is different than the pull-tester that came before it in a few +ways. + +There is nothing to administer. This is a major feature as it means +that builds have no local state. Because there is no ability to login to the +builders to install packages (tools, dependencies, etc), the entire build +procedure must instead be controlled by a declarative script (.travis.yml). +This script declares each build configuration, creates virtual machines as +necessary, builds, then discards the virtual machines. + +A build matrix is constructed to test a wide range of configurations, rather +than a single pass/fail. This helps to catch build failures and logic errors +that present on platforms other than the ones the author has tested. This +matrix is defined in the build script and can be changed at any time. + +All builders use the dependency-generator in the depends dir, rather than +using apt-get to install build dependencies. This guarantees that the tester +is using the same versions as Gitian, so the build results are nearly identical +to what would be found in a final release. However, this also means that builds +will fail if new dependencies are introduced without being added to the +dependency generator. + +In order to avoid rebuilding all dependencies for each build, the binaries are +cached and re-used when possible. Changes in the dependency-generator will +trigger cache-invalidation and rebuilds as necessary. + +These caches can be manually removed if necessary. This is one of the the very few +manual operations that is possible with Travis, and it can be done by the +Bitcoin Core committer via the Travis web interface. + +In some cases, secure strings may be needed for hiding sensitive info such as +private keys or URLs. The travis client may be used to create these strings: +http://docs.travis-ci.com/user/encryption-keys/ + +For the details of the build descriptor, see the official docs: +http://docs.travis-ci.com/user/build-configuration/ diff --git a/qa/pull-tester/run-bitcoind-for-test.sh.in b/qa/pull-tester/run-bitcoind-for-test.sh.in index e186bd7a23..67318e5a4c 100755 --- a/qa/pull-tester/run-bitcoind-for-test.sh.in +++ b/qa/pull-tester/run-bitcoind-for-test.sh.in @@ -9,7 +9,7 @@ mkdir -p "$DATADIR"/regtest touch "$DATADIR/regtest/debug.log" tail -q -n 1 -F "$DATADIR/regtest/debug.log" | grep -m 1 -q "Done loading" & WAITER=$! -PORT=`expr 10000 + $BASHPID % 55536` +PORT=`expr 10000 + $$ % 55536` "@abs_top_builddir@/src/bitcoind@EXEEXT@" -connect=0.0.0.0 -datadir="$DATADIR" -rpcuser=user -rpcpassword=pass -listen -keypool=3 -debug -debug=net -logtimestamps -port=$PORT -whitelist=127.0.0.1 -regtest -rpcport=`expr $PORT + 1` & BITCOIND=$! diff --git a/src/Makefile.am b/src/Makefile.am index 727a88c3e7..655bfc88c3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,3 @@ -AM_CPPFLAGS = $(INCLUDES) AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) if USE_LIBSECP256K1 @@ -22,7 +21,7 @@ $(LIBLEVELDB) $(LIBMEMENV): endif BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config -BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) +BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) if USE_LIBSECP256K1 BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include @@ -56,12 +55,10 @@ if BUILD_BITCOIND bin_PROGRAMS += bitcoind endif -if BUILD_BITCOIN_CLI - bin_PROGRAMS += bitcoin-cli +if BUILD_BITCOIN_UTILS + bin_PROGRAMS += bitcoin-cli bitcoin-tx endif -bin_PROGRAMS += bitcoin-tx - .PHONY: FORCE # bitcoin core # BITCOIN_CORE_H = \ @@ -112,6 +109,9 @@ BITCOIN_CORE_H = \ ui_interface.h \ uint256.h \ util.h \ + utilstrencodings.h \ + utilmoneystr.h \ + utiltime.h \ version.h \ walletdb.h \ wallet.h \ @@ -188,6 +188,7 @@ univalue_libbitcoin_univalue_a_SOURCES = \ univalue/univalue.cpp \ univalue/univalue_read.cpp \ univalue/univalue_write.cpp \ + univalue/univalue_escapes.h \ univalue/univalue.h # common: shared between bitcoind, and bitcoin-qt and non-server tools @@ -221,6 +222,9 @@ libbitcoin_util_a_SOURCES = \ sync.cpp \ uint256.cpp \ util.cpp \ + utilstrencodings.cpp \ + utilmoneystr.cpp \ + utiltime.cpp \ version.cpp \ $(BITCOIN_CORE_H) @@ -230,6 +234,7 @@ libbitcoin_util_a_SOURCES += compat/glibcxx_compat.cpp endif # cli: shared between bitcoin-cli and bitcoin-qt +libbitcoin_cli_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_cli_a_SOURCES = \ rpcclient.cpp \ $(BITCOIN_CORE_H) @@ -261,8 +266,9 @@ if TARGET_WINDOWS bitcoind_SOURCES += bitcoind-res.rc endif -bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) +bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES) +bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) # bitcoin-cli binary # bitcoin_cli_LDADD = \ @@ -270,7 +276,10 @@ bitcoin_cli_LDADD = \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ - $(BOOST_LIBS) + $(BOOST_LIBS) \ + $(SSL_LIBS) \ + $(CRYPTO_LIBS) + bitcoin_cli_SOURCES = \ bitcoin-cli.cpp @@ -285,15 +294,24 @@ bitcoin_tx_LDADD = \ $(LIBBITCOIN_UNIVALUE) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ - $(LIBBITCOIN_CRYPTO) \ - $(BOOST_LIBS) + $(LIBBITCOIN_CRYPTO) + +if USE_LIBSECP256K1 + bitcoin_tx_LDADD += secp256k1/libsecp256k1.la +endif + + bitcoin_tx_LDADD += $(BOOST_LIBS) \ + $(SSL_LIBS) \ + $(CRYPTO_LIBS) bitcoin_tx_SOURCES = bitcoin-tx.cpp bitcoin_tx_CPPFLAGS = $(BITCOIN_INCLUDES) # +bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) if TARGET_WINDOWS bitcoin_cli_SOURCES += bitcoin-cli-res.rc endif +bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 7e6fa5cb88..1ea039adb3 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -233,6 +233,9 @@ RES_ICONS = \ qt/res/icons/editcopy.png \ qt/res/icons/editpaste.png \ qt/res/icons/export.png \ + qt/res/icons/eye.png \ + qt/res/icons/eye_minus.png \ + qt/res/icons/eye_plus.png \ qt/res/icons/filesave.png \ qt/res/icons/history.png \ qt/res/icons/key.png \ @@ -358,11 +361,11 @@ if ENABLE_WALLET qt_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET) endif qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ - $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) + $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) if USE_LIBSECP256K1 qt_bitcoin_qt_LDADD += secp256k1/libsecp256k1.la endif -qt_bitcoin_qt_LDFLAGS = $(AM_LDFLAGS) $(QT_LDFLAGS) +qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) #locale/foo.ts -> locale/foo.qm QT_QM=$(QT_TS:.ts=.qm) diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index d49b2240ea..2cba5b7e1e 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -32,11 +32,11 @@ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET) endif qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \ $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ - $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) + $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) if USE_LIBSECP256K1 qt_test_test_bitcoin_qt_LDADD += secp256k1/libsecp256k1.la endif -qt_test_test_bitcoin_qt_LDFLAGS = $(AM_LDFLAGS) $(QT_LDFLAGS) +qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 72451fba9a..b4360831bb 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -1,8 +1,20 @@ -TESTS += test/test_bitcoin +TESTS += test/test_bitcoin test/bitcoin-util-test.py bin_PROGRAMS += test/test_bitcoin TEST_SRCDIR = test TEST_BINARY=test/test_bitcoin$(EXEEXT) + +EXTRA_DIST += \ + test/bctest.py \ + test/bitcoin-util-test.py \ + test/data/bitcoin-util-test.json \ + test/data/blanktx.hex \ + test/data/tt-delin1-out.hex \ + test/data/tt-delout1-out.hex \ + test/data/tt-locktime317000-out.hex \ + test/data/tx394b54bb.hex \ + test/data/txcreate1.hex + JSON_TEST_FILES = \ test/data/script_valid.json \ test/data/base58_keys_valid.json \ @@ -49,8 +61,10 @@ BITCOIN_TESTS =\ test/sigopcount_tests.cpp \ test/skiplist_tests.cpp \ test/test_bitcoin.cpp \ + test/timedata_tests.cpp \ test/transaction_tests.cpp \ test/uint256_tests.cpp \ + test/univalue_tests.cpp \ test/util_tests.cpp \ test/scriptnum_tests.cpp \ test/sighash_tests.cpp @@ -74,7 +88,8 @@ if USE_LIBSECP256K1 test_test_bitcoin_LDADD += secp256k1/libsecp256k1.la endif -test_test_bitcoin_LDADD += $(BDB_LIBS) +test_test_bitcoin_LDADD += $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) +test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) diff --git a/src/addrman.cpp b/src/addrman.cpp index 3628af2eab..704766dbf8 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -492,17 +492,23 @@ int CAddrMan::Check_() void CAddrMan::GetAddr_(std::vector<CAddress> &vAddr) { - int nNodes = ADDRMAN_GETADDR_MAX_PCT*vRandom.size()/100; + unsigned int nNodes = ADDRMAN_GETADDR_MAX_PCT * vRandom.size() / 100; if (nNodes > ADDRMAN_GETADDR_MAX) nNodes = ADDRMAN_GETADDR_MAX; - // perform a random shuffle over the first nNodes elements of vRandom (selecting from all) - for (int n = 0; n<nNodes; n++) + // gather a list of random nodes, skipping those of low quality + for (unsigned int n = 0; n < vRandom.size(); n++) { + if (vAddr.size() >= nNodes) + break; + int nRndPos = GetRandInt(vRandom.size() - n) + n; SwapRandom(n, nRndPos); assert(mapInfo.count(vRandom[n]) == 1); - vAddr.push_back(mapInfo[vRandom[n]]); + + const CAddrInfo& ai = mapInfo[vRandom[n]]; + if (!ai.IsTerrible()) + vAddr.push_back(ai); } } diff --git a/src/alert.cpp b/src/alert.cpp index 258a2b52c4..3271ecfbfd 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -19,6 +19,7 @@ #include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/replace.hpp> #include <boost/foreach.hpp> +#include <boost/thread.hpp> using namespace std; @@ -80,11 +81,6 @@ std::string CUnsignedAlert::ToString() const strStatusBar); } -void CUnsignedAlert::print() const -{ - LogPrintf("%s", ToString()); -} - void CAlert::SetNull() { CUnsignedAlert::SetNull(); diff --git a/src/alert.h b/src/alert.h index da140be5e5..b9d850b565 100644 --- a/src/alert.h +++ b/src/alert.h @@ -60,15 +60,14 @@ public: READWRITE(setSubVer); READWRITE(nPriority); - READWRITE(strComment); - READWRITE(strStatusBar); - READWRITE(strReserved); + READWRITE(LIMITED_STRING(strComment, 65536)); + READWRITE(LIMITED_STRING(strStatusBar, 256)); + READWRITE(LIMITED_STRING(strReserved, 256)); ) void SetNull(); std::string ToString() const; - void print() const; }; /** An alert is a combination of a serialized CUnsignedAlert and a signature. */ diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 0609adcab3..871aaf93df 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -8,6 +8,8 @@ #include "rpcclient.h" #include "rpcprotocol.h" #include "chainparamsbase.h" +#include "utilstrencodings.h" +#include "version.h" #include <boost/filesystem/operations.hpp> diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index ffe87298f6..75f0fb69f2 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -4,6 +4,7 @@ #include "base58.h" #include "util.h" +#include "utilmoneystr.h" #include "core.h" #include "main.h" // for MAX_BLOCK_SIZE #include "keystore.h" @@ -13,6 +14,7 @@ #include <stdio.h> #include <boost/assign/list_of.hpp> +#include <boost/algorithm/string.hpp> using namespace std; using namespace boost::assign; @@ -501,13 +503,34 @@ static void OutputTx(const CTransaction& tx) OutputTxHex(tx); } +static string readStdin() +{ + char buf[4096]; + string ret; + + while (!feof(stdin)) { + size_t bread = fread(buf, 1, sizeof(buf), stdin); + ret.append(buf, bread); + if (bread < sizeof(buf)) + break; + } + + if (ferror(stdin)) + throw runtime_error("error reading stdin"); + + boost::algorithm::trim_right(ret); + + return ret; +} + static int CommandLineRawTx(int argc, char* argv[]) { string strPrint; int nRet = 0; try { - // Skip switches - while (argc > 1 && IsSwitchChar(argv[1][0])) { + // Skip switches; Permit common stdin convention "-" + while (argc > 1 && IsSwitchChar(argv[1][0]) && + (argv[1][1] != 0)) { argc--; argv++; } @@ -522,6 +545,8 @@ static int CommandLineRawTx(int argc, char* argv[]) // param: hex-encoded bitcoin transaction string strHexTx(argv[1]); + if (strHexTx == "-") // "-" implies standard input + strHexTx = readStdin(); if (!DecodeHexTx(txDecodeTmp, strHexTx)) throw runtime_error("invalid transaction encoding"); diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 880955481b..5be8708979 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -12,6 +12,7 @@ #include <boost/algorithm/string/predicate.hpp> #include <boost/filesystem.hpp> +#include <boost/thread.hpp> /* Introduction text for doxygen: */ diff --git a/src/bloom.h b/src/bloom.h index d0caf9e9fa..54d16d7126 100644 --- a/src/bloom.h +++ b/src/bloom.h @@ -60,7 +60,7 @@ public: // It should generally always be a random value (and is largely only exposed for unit testing) // nFlags should be one of the BLOOM_UPDATE_* enums (not _MASK) CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweak, unsigned char nFlagsIn); - CBloomFilter() : isFull(true) {} + CBloomFilter() : isFull(true), isEmpty(false), nHashFuncs(0), nTweak(0), nFlags(0) {} IMPLEMENT_SERIALIZE ( diff --git a/src/coins.cpp b/src/coins.cpp index fe40911db7..7bfb84ef3e 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -52,30 +52,30 @@ bool CCoins::Spend(int nPos) { } -bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) { return false; } +bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; } bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; } -bool CCoinsView::HaveCoins(const uint256 &txid) { return false; } -uint256 CCoinsView::GetBestBlock() { return uint256(0); } +bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; } +uint256 CCoinsView::GetBestBlock() const { return uint256(0); } bool CCoinsView::SetBestBlock(const uint256 &hashBlock) { return false; } -bool CCoinsView::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; } -bool CCoinsView::GetStats(CCoinsStats &stats) { return false; } +bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; } +bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; } CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { } -bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) { return base->GetCoins(txid, coins); } +bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); } bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); } -bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(txid); } -uint256 CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); } +bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); } +uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); } bool CCoinsViewBacked::SetBestBlock(const uint256 &hashBlock) { return base->SetBestBlock(hashBlock); } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } -bool CCoinsViewBacked::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } -bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stats); } +bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } +bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); } CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {} CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), hashBlock(0) { } -bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) { +bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const { if (cacheCoins.count(txid)) { coins = cacheCoins[txid]; return true; @@ -99,19 +99,29 @@ CCoinsMap::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) { return ret; } +CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const { + /* Avoid redundant implementation with the const-cast. */ + return const_cast<CCoinsViewCache*>(this)->FetchCoins(txid); +} + CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) { CCoinsMap::iterator it = FetchCoins(txid); assert(it != cacheCoins.end()); return it->second; } +const CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) const { + /* Avoid redundant implementation with the const-cast. */ + return const_cast<CCoinsViewCache*>(this)->GetCoins(txid); +} + bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) { cacheCoins[txid] = coins; return true; } -bool CCoinsViewCache::HaveCoins(const uint256 &txid) { - CCoinsMap::iterator it = FetchCoins(txid); +bool CCoinsViewCache::HaveCoins(const uint256 &txid) const { + CCoinsMap::const_iterator it = FetchCoins(txid); // We're using vtx.empty() instead of IsPruned here for performance reasons, // as we only care about the case where an transaction was replaced entirely // in a reorganization (which wipes vout entirely, as opposed to spending @@ -119,7 +129,7 @@ bool CCoinsViewCache::HaveCoins(const uint256 &txid) { return (it != cacheCoins.end() && !it->second.vout.empty()); } -uint256 CCoinsViewCache::GetBestBlock() { +uint256 CCoinsViewCache::GetBestBlock() const { if (hashBlock == uint256(0)) hashBlock = base->GetBestBlock(); return hashBlock; @@ -130,32 +140,34 @@ bool CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { return true; } -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; +bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) { + for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { + cacheCoins[it->first].swap(it->second); + CCoinsMap::iterator itOld = it++; + mapCoins.erase(itOld); + } hashBlock = hashBlockIn; return true; } bool CCoinsViewCache::Flush() { bool fOk = base->BatchWrite(cacheCoins, hashBlock); - if (fOk) - cacheCoins.clear(); + cacheCoins.clear(); return fOk; } -unsigned int CCoinsViewCache::GetCacheSize() { +unsigned int CCoinsViewCache::GetCacheSize() const { return cacheCoins.size(); } -const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) +const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const { const CCoins &coins = GetCoins(input.prevout.hash); assert(coins.IsAvailable(input.prevout.n)); return coins.vout[input.prevout.n]; } -int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx) +int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx) const { if (tx.IsCoinBase()) return 0; @@ -167,7 +179,7 @@ int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx) return nResult; } -bool CCoinsViewCache::HaveInputs(const CTransaction& tx) +bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const { if (!tx.IsCoinBase()) { // first check whether information about the prevout hash is available @@ -188,7 +200,7 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) return true; } -double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) +double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const { if (tx.IsCoinBase()) return 0.0; diff --git a/src/coins.h b/src/coins.h index ff60288163..08913531d8 100644 --- a/src/coins.h +++ b/src/coins.h @@ -276,26 +276,27 @@ class CCoinsView { public: // Retrieve the CCoins (unspent transaction outputs) for a given txid - virtual bool GetCoins(const uint256 &txid, CCoins &coins); + virtual bool GetCoins(const uint256 &txid, CCoins &coins) const; // Modify the CCoins for a given txid virtual bool SetCoins(const uint256 &txid, const CCoins &coins); // Just check whether we have data for a given txid. // This may (but cannot always) return true for fully spent transactions - virtual bool HaveCoins(const uint256 &txid); + virtual bool HaveCoins(const uint256 &txid) const; // Retrieve the block hash whose state this CCoinsView currently represents - virtual uint256 GetBestBlock(); + virtual uint256 GetBestBlock() const; // Modify the currently active block hash virtual bool SetBestBlock(const uint256 &hashBlock); - // Do a bulk modification (multiple SetCoins + one SetBestBlock) - virtual bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock); + // Do a bulk modification (multiple SetCoins + one SetBestBlock). + // The passed mapCoins can be modified. + virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); // Calculate statistics about the unspent transaction output set - virtual bool GetStats(CCoinsStats &stats); + virtual bool GetStats(CCoinsStats &stats) const; // As we use CCoinsViews polymorphically, have a virtual destructor virtual ~CCoinsView() {} @@ -310,14 +311,14 @@ protected: public: CCoinsViewBacked(CCoinsView &viewIn); - bool GetCoins(const uint256 &txid, CCoins &coins); + bool GetCoins(const uint256 &txid, CCoins &coins) const; bool SetCoins(const uint256 &txid, const CCoins &coins); - bool HaveCoins(const uint256 &txid); - uint256 GetBestBlock(); + bool HaveCoins(const uint256 &txid) const; + uint256 GetBestBlock() const; bool SetBestBlock(const uint256 &hashBlock); void SetBackend(CCoinsView &viewIn); - bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock); - bool GetStats(CCoinsStats &stats); + bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); + bool GetStats(CCoinsStats &stats) const; }; @@ -325,31 +326,36 @@ public: class CCoinsViewCache : public CCoinsViewBacked { protected: - uint256 hashBlock; - CCoinsMap cacheCoins; + + /* Make mutable so that we can "fill the cache" even from Get-methods + declared as "const". */ + mutable uint256 hashBlock; + mutable CCoinsMap cacheCoins; public: CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false); // Standard CCoinsView methods - bool GetCoins(const uint256 &txid, CCoins &coins); + bool GetCoins(const uint256 &txid, CCoins &coins) const; bool SetCoins(const uint256 &txid, const CCoins &coins); - bool HaveCoins(const uint256 &txid); - uint256 GetBestBlock(); + bool HaveCoins(const uint256 &txid) const; + uint256 GetBestBlock() const; bool SetBestBlock(const uint256 &hashBlock); - bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock); + bool BatchWrite(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 // copying. CCoins &GetCoins(const uint256 &txid); + const CCoins &GetCoins(const uint256 &txid) const; // Push the modifications applied to this cache to its base. // Failure to call this method before destruction will cause the changes to be forgotten. + // If false is returned, the state of this cache (and its backing view) will be undefined. bool Flush(); // Calculate the size of the cache (in number of transactions) - unsigned int GetCacheSize(); + unsigned int GetCacheSize() const; /** Amount of bitcoins coming in to a transaction Note that lightweight clients may not know anything besides the hash of previous transactions, @@ -358,18 +364,19 @@ public: @param[in] tx transaction for which we are checking input total @return Sum of value of all inputs (scriptSigs) */ - int64_t GetValueIn(const CTransaction& tx); + int64_t GetValueIn(const CTransaction& tx) const; // Check whether all prevouts of the transaction are present in the UTXO set represented by this view - bool HaveInputs(const CTransaction& tx); + bool HaveInputs(const CTransaction& tx) const; // Return priority of tx at height nHeight - double GetPriority(const CTransaction &tx, int nHeight); + double GetPriority(const CTransaction &tx, int nHeight) const; - const CTxOut &GetOutputFor(const CTxIn& input); + const CTxOut &GetOutputFor(const CTxIn& input) const; private: CCoinsMap::iterator FetchCoins(const uint256 &txid); + CCoinsMap::const_iterator FetchCoins(const uint256 &txid) const; }; #endif diff --git a/src/compat.h b/src/compat.h index 52c7817130..4fc28a36e0 100644 --- a/src/compat.h +++ b/src/compat.h @@ -59,4 +59,29 @@ typedef u_int SOCKET; #define SOCKET_ERROR -1 #endif +#ifdef WIN32 +#ifndef S_IRUSR +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#endif +#else +#define MAX_PATH 1024 +#endif + +// As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0 +#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) +#define MSG_NOSIGNAL 0 +#endif + +#ifndef WIN32 +// PRIO_MAX is not defined on Solaris +#ifndef PRIO_MAX +#define PRIO_MAX 20 +#endif +#define THREAD_PRIORITY_LOWEST PRIO_MAX +#define THREAD_PRIORITY_BELOW_NORMAL 2 +#define THREAD_PRIORITY_NORMAL 0 +#define THREAD_PRIORITY_ABOVE_NORMAL (-2) +#endif + #endif // _BITCOIN_COMPAT_H diff --git a/src/core.cpp b/src/core.cpp index 149b3532a1..71d6fea610 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -5,18 +5,13 @@ #include "core.h" -#include "util.h" +#include "tinyformat.h" std::string COutPoint::ToString() const { return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n); } -void COutPoint::print() const -{ - LogPrintf("%s\n", ToString()); -} - CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, unsigned int nSequenceIn) { prevout = prevoutIn; @@ -46,11 +41,6 @@ std::string CTxIn::ToString() const return str; } -void CTxIn::print() const -{ - LogPrintf("%s\n", ToString()); -} - CTxOut::CTxOut(int64_t nValueIn, CScript scriptPubKeyIn) { nValue = nValueIn; @@ -67,11 +57,6 @@ std::string CTxOut::ToString() const return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30)); } -void CTxOut::print() const -{ - LogPrintf("%s\n", ToString()); -} - CFeeRate::CFeeRate(int64_t nFeePaid, size_t nSize) { if (nSize > 0) @@ -92,8 +77,7 @@ int64_t CFeeRate::GetFee(size_t nSize) const std::string CFeeRate::ToString() const { - std::string result = FormatMoney(nSatoshisPerK) + " BTC/kB"; - return result; + return strprintf("%d.%08d BTC/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN); } CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {} @@ -171,11 +155,6 @@ std::string CTransaction::ToString() const return str; } -void CTransaction::print() const -{ - LogPrintf("%s", ToString()); -} - // Amount compression: // * If the amount is 0, output 0 // * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9) @@ -285,9 +264,10 @@ uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMer return hash; } -void CBlock::print() const +std::string CBlock::ToString() const { - LogPrintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n", + std::stringstream s; + s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), @@ -296,11 +276,11 @@ void CBlock::print() const vtx.size()); for (unsigned int i = 0; i < vtx.size(); i++) { - LogPrintf(" "); - vtx[i].print(); + s << " " << vtx[i].ToString() << "\n"; } - LogPrintf(" vMerkleTree: "); + s << " vMerkleTree: "; for (unsigned int i = 0; i < vMerkleTree.size(); i++) - LogPrintf("%s ", vMerkleTree[i].ToString()); - LogPrintf("\n"); + s << " " << vMerkleTree[i].ToString(); + s << "\n"; + return s.str(); } diff --git a/src/core.h b/src/core.h index fb64e6c08e..e3ceac97aa 100644 --- a/src/core.h +++ b/src/core.h @@ -14,6 +14,9 @@ class CTransaction; +static const int64_t COIN = 100000000; +static const int64_t CENT = 1000000; + /** No amount larger than this (in satoshi) is valid */ static const int64_t MAX_MONEY = 21000000 * COIN; inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } @@ -47,7 +50,6 @@ public: } std::string ToString() const; - void print() const; }; /** An inpoint - a combination of a transaction and an index n into its vin */ @@ -107,7 +109,6 @@ public: } std::string ToString() const; - void print() const; }; @@ -200,7 +201,6 @@ public: } std::string ToString() const; - void print() const; }; @@ -279,7 +279,6 @@ public: } std::string ToString() const; - void print() const; }; /** A mutable version of CTransaction. */ @@ -497,7 +496,7 @@ public: std::vector<uint256> GetMerkleBranch(int nIndex) const; static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex); - void print() const; + std::string ToString() const; }; diff --git a/src/core_write.cpp b/src/core_write.cpp index 37dd69f7b8..b395b5c090 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -8,6 +8,7 @@ #include "core.h" #include "serialize.h" #include "util.h" +#include "utilmoneystr.h" #include "base58.h" using namespace std; diff --git a/src/crypter.cpp b/src/crypter.cpp index 4c43e3a798..8aa2bb0517 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -5,6 +5,7 @@ #include "crypter.h" #include "script.h" +#include "util.h" #include <string> #include <vector> @@ -152,6 +153,8 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) if (!SetCrypted()) return false; + bool keyPass = false; + bool keyFail = false; CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin(); for (; mi != mapCryptedKeys.end(); ++mi) { @@ -159,16 +162,35 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second; CKeyingMaterial vchSecret; if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) - return false; + { + keyFail = true; + break; + } if (vchSecret.size() != 32) - return false; + { + keyFail = true; + break; + } CKey key; key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); - if (key.GetPubKey() == vchPubKey) + if (key.GetPubKey() != vchPubKey) + { + keyFail = true; break; - return false; + } + keyPass = true; + if (fDecryptionThoroughlyChecked) + break; + } + if (keyPass && keyFail) + { + LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all."); + assert(false); } + if (keyFail || !keyPass) + return false; vMasterKey = vMasterKeyIn; + fDecryptionThoroughlyChecked = true; } NotifyStatusChanged(this); return true; diff --git a/src/crypter.h b/src/crypter.h index 4791428b48..f16fcef9c7 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -121,6 +121,9 @@ private: // if fUseCrypto is false, vMasterKey must be empty bool fUseCrypto; + // keeps track of whether Unlock has run a thourough check before + bool fDecryptionThoroughlyChecked; + protected: bool SetCrypted(); @@ -130,7 +133,7 @@ protected: bool Unlock(const CKeyingMaterial& vMasterKeyIn); public: - CCryptoKeyStore() : fUseCrypto(false) + CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false) { } diff --git a/src/db.cpp b/src/db.cpp index eb40f3cc40..23d2cc988d 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -9,6 +9,7 @@ #include "hash.h" #include "protocol.h" #include "util.h" +#include "utilstrencodings.h" #include <stdint.h> @@ -17,6 +18,7 @@ #endif #include <boost/filesystem.hpp> +#include <boost/thread.hpp> #include <boost/version.hpp> #include <openssl/rand.h> @@ -225,10 +227,10 @@ CDB::CDB(const char *pszFile, const char* pszMode) : pdb(NULL), activeTxn(NULL) { int ret; + fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); if (pszFile == NULL) return; - fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); bool fCreate = strchr(pszMode, 'c'); unsigned int nFlags = DB_THREAD; if (fCreate) @@ -17,7 +17,6 @@ #include <boost/filesystem/path.hpp> #include <db_cxx.h> -class CAddrMan; struct CBlockLocator; class CDiskBlockIndex; class COutPoint; diff --git a/src/init.cpp b/src/init.cpp index 494342c693..c49083c7df 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -19,6 +19,7 @@ #include "txdb.h" #include "ui_interface.h" #include "util.h" +#include "utilmoneystr.h" #ifdef ENABLE_WALLET #include "db.h" #include "wallet.h" @@ -36,6 +37,7 @@ #include <boost/algorithm/string/predicate.hpp> #include <boost/filesystem.hpp> #include <boost/interprocess/sync/file_lock.hpp> +#include <boost/thread.hpp> #include <openssl/crypto.h> using namespace boost; @@ -247,7 +249,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += " -maxreceivebuffer=<n> " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)") + "\n"; strUsage += " -maxsendbuffer=<n> " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)") + "\n"; strUsage += " -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 += " -onlynet=<net> " + _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)") + "\n"; strUsage += " -permitbaremultisig " + _("Relay non-P2SH multisig (default: 1)") + "\n"; strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n"; strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS5 proxy") + "\n"; @@ -1037,8 +1039,7 @@ bool AppInit2(boost::thread_group& threadGroup) CBlock block; ReadBlockFromDisk(block, pindex); block.BuildMerkleTree(); - block.print(); - LogPrintf("\n"); + LogPrintf("%s\n", block.ToString()); nFound++; } } @@ -189,7 +189,7 @@ private: public: // Construct an invalid private key. - CKey() : fValid(false) { + CKey() : fValid(false), fCompressed(false) { LockObject(vch); } diff --git a/src/keystore.cpp b/src/keystore.cpp index 2a4c88d565..72ae9b0a30 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -8,6 +8,7 @@ #include "crypter.h" #include "key.h" #include "script.h" +#include "util.h" #include <boost/foreach.hpp> @@ -71,3 +72,9 @@ bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const LOCK(cs_KeyStore); return setWatchOnly.count(dest) > 0; } + +bool CBasicKeyStore::HaveWatchOnly() const +{ + LOCK(cs_KeyStore); + return (!setWatchOnly.empty()); +} diff --git a/src/keystore.h b/src/keystore.h index 6a3a0dc13e..7aaf197cd7 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -41,6 +41,7 @@ public: // Support for Watch-only addresses virtual bool AddWatchOnly(const CScript &dest) =0; virtual bool HaveWatchOnly(const CScript &dest) const =0; + virtual bool HaveWatchOnly() const =0; }; typedef std::map<CKeyID, CKey> KeyMap; @@ -98,6 +99,7 @@ public: virtual bool AddWatchOnly(const CScript &dest); virtual bool HaveWatchOnly(const CScript &dest) const; + virtual bool HaveWatchOnly() const; }; typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial; diff --git a/src/leveldbwrapper.h b/src/leveldbwrapper.h index 043a56bf38..452df92839 100644 --- a/src/leveldbwrapper.h +++ b/src/leveldbwrapper.h @@ -82,7 +82,7 @@ public: CLevelDBWrapper(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory = false, bool fWipe = false); ~CLevelDBWrapper(); - template<typename K, typename V> bool Read(const K& key, V& value) throw(leveldb_error) { + template<typename K, typename V> bool Read(const K& key, V& value) const throw(leveldb_error) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(ssKey.GetSerializeSize(key)); ssKey << key; @@ -111,7 +111,7 @@ public: return WriteBatch(batch, fSync); } - template<typename K> bool Exists(const K& key) throw(leveldb_error) { + template<typename K> bool Exists(const K& key) const throw(leveldb_error) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(ssKey.GetSerializeSize(key)); ssKey << key; diff --git a/src/m4/ax_boost_base.m4 b/src/m4/ax_boost_base.m4 index e025a7e1ca..3f24d5ddc6 100644 --- a/src/m4/ax_boost_base.m4 +++ b/src/m4/ax_boost_base.m4 @@ -112,6 +112,12 @@ if test "x$want_boost" = "xyes"; then ;; esac + dnl some arches may advertise a cpu type that doesn't line up with their + dnl prefix's cpu type. For example, uname may report armv7l while libs are + dnl installed to /usr/lib/arm-linux-gnueabihf. Try getting the compiler's + dnl value for an extra chance of finding the correct path. + libsubdirs="lib/`$CXX -dumpmachine 2>/dev/null` $libsubdirs" + dnl first we check the system location for boost libraries dnl this location ist chosen if boost libraries are installed with the --layout=system option dnl or if you install boost with RPM diff --git a/src/m4/bitcoin_qt.m4 b/src/m4/bitcoin_qt.m4 index 4c1d40c394..e141033b19 100644 --- a/src/m4/bitcoin_qt.m4 +++ b/src/m4/bitcoin_qt.m4 @@ -48,8 +48,8 @@ dnl CAUTION: Do not use this inside of a conditional. AC_DEFUN([BITCOIN_QT_INIT],[ dnl enable qt support AC_ARG_WITH([gui], - [AS_HELP_STRING([--with-gui], - [with GUI (no|qt4|qt5|auto. default is auto, qt4 tried first.)])], + [AS_HELP_STRING([--with-gui@<:@=no|qt4|qt5|auto@:>@], + [build bitcoin-qt GUI (default=auto, qt4 tried first)])], [ bitcoin_qt_want_version=$withval if test x$bitcoin_qt_want_version = xyes; then @@ -112,11 +112,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) if test x$qt_plugin_path != x; then QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" - if test x$bitcoin_qt_got_major_vers == x5; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" - else - QT_LIBS="$QT_LIBS -L$qt_plugin_path/codecs" - fi + QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" fi if test x$use_pkgconfig = xyes; then PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"]) @@ -141,6 +137,10 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ else if test x$TARGET_OS == xwindows; then AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) + if test x$qt_plugin_path != x; then + QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" + QT_LIBS="$QT_LIBS -L$qt_plugin_path/codecs" + fi _BITCOIN_QT_CHECK_STATIC_PLUGINS([ Q_IMPORT_PLUGIN(qcncodecs) Q_IMPORT_PLUGIN(qjpcodecs) diff --git a/src/main.cpp b/src/main.cpp index 841cc1952f..81989d7faf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ #include <boost/algorithm/string/replace.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> +#include <boost/thread.hpp> using namespace std; using namespace boost; @@ -643,7 +644,7 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) // 2. P2SH scripts with a crazy number of expensive // CHECKSIG/CHECKMULTISIG operations // -bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs) +bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) { if (tx.IsCoinBase()) return true; // Coinbases don't use vin normally @@ -716,7 +717,7 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx) return nSigOps; } -unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& inputs) +unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs) { if (tx.IsCoinBase()) return 0; @@ -1022,7 +1023,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa pool.addUnchecked(hash, entry); } - g_signals.SyncTransaction(tx, NULL); + SyncWithWallets(tx, NULL); return true; } @@ -1417,25 +1418,6 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state } } -void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev) -{ - block.nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - - // Updating time can change work required on testnet: - if (Params().AllowMinDifficultyBlocks()) - block.nBits = GetNextWorkRequired(pindexPrev, &block); -} - - - - - - - - - - - void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight) { bool ret; @@ -1467,7 +1449,7 @@ bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned in return CScriptCheck(txFrom, txTo, nIn, flags, nHashType)(); } -bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks) +bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks) { if (!tx.IsCoinBase()) { @@ -1855,10 +1837,6 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C int64_t nTime3 = GetTimeMicros(); nTimeIndex += nTime3 - nTime2; LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeIndex * 0.000001); - // Watch for transactions paying to me - 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); @@ -1976,15 +1954,19 @@ static int64_t nTimeFlush = 0; static int64_t nTimeChainState = 0; static int64_t nTimePostConnect = 0; -// Connect a new block to chainActive. -bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { +// Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock +// corresponding to pindexNew, to bypass loading it again from disk. +bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) { assert(pindexNew->pprev == chainActive.Tip()); mempool.check(pcoinsTip); // Read block from disk. int64_t nTime1 = GetTimeMicros(); CBlock block; - if (!ReadBlockFromDisk(block, pindexNew)) - return state.Abort(_("Failed to read block")); + if (!pblock) { + if (!ReadBlockFromDisk(block, pindexNew)) + return state.Abort(_("Failed to read block")); + pblock = █ + } // Apply the block atomically to the chain state. int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1; int64_t nTime3; @@ -1992,7 +1974,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { { CCoinsViewCache view(*pcoinsTip, true); CInv inv(MSG_BLOCK, pindexNew->GetBlockHash()); - if (!ConnectBlock(block, state, pindexNew, view)) { + if (!ConnectBlock(*pblock, state, pindexNew, view)) { if (state.IsInvalid()) InvalidBlockFound(pindexNew, state); return error("ConnectTip() : ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); @@ -2011,7 +1993,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); // Remove conflicting transactions from the mempool. list<CTransaction> txConflicted; - mempool.removeForBlock(block.vtx, pindexNew->nHeight, txConflicted); + mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted); mempool.check(pcoinsTip); // Update chainActive & related variables. UpdateTip(pindexNew); @@ -2021,8 +2003,8 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { SyncWithWallets(tx, NULL); } // ... and about transactions that got confirmed: - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - SyncWithWallets(tx, &block); + BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { + SyncWithWallets(tx, pblock); } int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); @@ -2071,7 +2053,8 @@ static CBlockIndex* FindMostWorkChain() { } // Try to make some progress towards making pindexMostWork the active block. -static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork) { +// pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. +static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, CBlock *pblock) { AssertLockHeld(cs_main); bool fInvalidFound = false; const CBlockIndex *pindexOldTip = chainActive.Tip(); @@ -2086,14 +2069,15 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo // 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; + CBlockIndex *pindexIter = pindexMostWork; + while (pindexIter && pindexIter != pindexFork) { + vpindexToConnect.push_back(pindexIter); + pindexIter = pindexIter->pprev; } // Connect new blocks. BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { - if (!ConnectTip(state, pindexConnect)) { + if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { if (state.IsInvalid()) { // The block violates a consensus rule. if (!state.CorruptionPossible()) @@ -2134,7 +2118,10 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo return true; } -bool ActivateBestChain(CValidationState &state) { +// Make the best chain active, in multiple steps. The result is either failure +// or an activated best chain. pblock is either NULL or a pointer to a block +// that is already loaded (to avoid loading it again from disk). +bool ActivateBestChain(CValidationState &state, CBlock *pblock) { CBlockIndex *pindexNewTip = NULL; CBlockIndex *pindexMostWork = NULL; do { @@ -2149,7 +2136,7 @@ bool ActivateBestChain(CValidationState &state) { if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) return true; - if (!ActivateBestChainStep(state, pindexMostWork)) + if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL)) return false; pindexNewTip = chainActive.Tip(); @@ -2424,12 +2411,7 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex 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) + if (!CheckMinWork(block.nBits, pcheckpoint->nBits, deltaTime)) { return state.DoS(100, error("CheckBlockHeader() : block with too little proof-of-work"), REJECT_INVALID, "bad-diffbits"); @@ -2694,7 +2676,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl } - if (!ActivateBestChain(state)) + if (!ActivateBestChain(state, pblock)) return error("ProcessBlock() : ActivateBestChain failed"); return true; @@ -3134,7 +3116,7 @@ bool InitBlockIndex() { CBlockIndex *pindex = AddToBlockIndex(block); if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("LoadBlockIndex() : genesis block not accepted"); - if (!ActivateBestChain(state)) + if (!ActivateBestChain(state, &block)) return error("LoadBlockIndex() : genesis block cannot be activated"); } catch(std::runtime_error &e) { return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); @@ -3232,7 +3214,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) } } uint64_t nRewind = blkdat.GetPos(); - while (blkdat.good() && !blkdat.eof()) { + while (!blkdat.eof()) { boost::this_thread::interruption_point(); blkdat.SetPos(nRewind); @@ -3286,15 +3268,6 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) return nLoaded > 0; } - - - - - - - - - ////////////////////////////////////////////////////////////////////////////// // // CAlert @@ -3563,7 +3536,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (!vRecv.empty()) vRecv >> addrFrom >> nNonce; if (!vRecv.empty()) { - vRecv >> pfrom->strSubVer; + vRecv >> LIMITED_STRING(pfrom->strSubVer, 256); pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); } if (!vRecv.empty()) @@ -3963,7 +3936,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> block; LogPrint("net", "received block %s peer=%d\n", block.GetHash().ToString(), pfrom->id); - // block.print(); CInv inv(MSG_BLOCK, block.GetHash()); pfrom->AddInventoryKnown(inv); @@ -4187,7 +4159,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (fDebug) { string strMsg; unsigned char ccode; string strReason; - vRecv >> strMsg >> ccode >> strReason; + vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, 111); ostringstream ss; ss << strMsg << " code " << itostr(ccode) << ": " << strReason; @@ -4198,10 +4170,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> hash; ss << ": hash " << hash.ToString(); } - // Truncate to reasonable length and sanitize before printing: - string s = ss.str(); - if (s.size() > 111) s.erase(111, string::npos); - LogPrint("net", "Reject %s\n", SanitizeString(s)); + LogPrint("net", "Reject %s\n", SanitizeString(ss.str())); } } @@ -4572,7 +4541,68 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } +bool CBlockUndo::WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock) +{ + // Open history file to append + CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); + if (!fileout) + return error("CBlockUndo::WriteToDisk : OpenUndoFile failed"); + + // Write index header + unsigned int nSize = fileout.GetSerializeSize(*this); + fileout << FLATDATA(Params().MessageStart()) << nSize; + + // Write undo data + long fileOutPos = ftell(fileout); + if (fileOutPos < 0) + return error("CBlockUndo::WriteToDisk : ftell failed"); + pos.nPos = (unsigned int)fileOutPos; + fileout << *this; + + // calculate & write checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << *this; + fileout << hasher.GetHash(); + + // Flush stdio buffers and commit to disk before returning + fflush(fileout); + if (!IsInitialBlockDownload()) + FileCommit(fileout); + + return true; +} + +bool CBlockUndo::ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock) +{ + // Open history file to read + CAutoFile filein = CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); + if (!filein) + return error("CBlockUndo::ReadFromDisk : OpenBlockFile failed"); + + // Read block + uint256 hashChecksum; + try { + filein >> *this; + filein >> hashChecksum; + } + catch (std::exception &e) { + return error("%s : Deserialize or I/O error - %s", __func__, e.what()); + } + + // Verify checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << *this; + if (hashChecksum != hasher.GetHash()) + return error("CBlockUndo::ReadFromDisk : Checksum mismatch"); + + return true; +} + std::string CBlockFileInfo::ToString() const { + return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst).c_str(), DateTimeStrFormat("%Y-%m-%d", nTimeLast).c_str()); + } diff --git a/src/main.h b/src/main.h index 01d3f119e1..3160b28c49 100644 --- a/src/main.h +++ b/src/main.h @@ -14,6 +14,7 @@ #include "coins.h" #include "core.h" #include "net.h" +#include "pow.h" #include "script.h" #include "sync.h" #include "txmempool.h" @@ -160,11 +161,9 @@ std::string GetWarnings(std::string strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false); /** Find the best known block, and make it the tip of the block chain */ -bool ActivateBestChain(CValidationState &state); +bool ActivateBestChain(CValidationState &state, CBlock *pblock = NULL); int64_t GetBlockValue(int nHeight, int64_t nFees); -void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev); - /** Create a new block index entry for a given block hash */ CBlockIndex * InsertBlockIndex(uint256 hash); /** Verify a signature */ @@ -265,7 +264,7 @@ int64_t GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF @param[in] mapInputs Map of previous transactions that have outputs we're spending @return True if all inputs (scriptSigs) use only standard transaction forms */ -bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs); +bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); /** Count ECDSA signature operations the old-fashioned (pre-0.6) way @return number of sigops this transaction's outputs will produce when spent @@ -279,13 +278,13 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx); @return maximum number of sigops required to validate this transaction's inputs @see CTransaction::FetchInputs */ -unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& mapInputs); +unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs); // 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, +bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks = true, unsigned int flags = STANDARD_SCRIPT_VERIFY_FLAGS, std::vector<CScriptCheck> *pvChecks = NULL); @@ -312,64 +311,8 @@ public: READWRITE(vtxundo); ) - bool WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock) - { - // Open history file to append - CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); - if (!fileout) - return error("CBlockUndo::WriteToDisk : OpenUndoFile failed"); - - // Write index header - unsigned int nSize = fileout.GetSerializeSize(*this); - fileout << FLATDATA(Params().MessageStart()) << nSize; - - // Write undo data - long fileOutPos = ftell(fileout); - if (fileOutPos < 0) - return error("CBlockUndo::WriteToDisk : ftell failed"); - pos.nPos = (unsigned int)fileOutPos; - fileout << *this; - - // calculate & write checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - hasher << hashBlock; - hasher << *this; - fileout << hasher.GetHash(); - - // Flush stdio buffers and commit to disk before returning - fflush(fileout); - if (!IsInitialBlockDownload()) - FileCommit(fileout); - - return true; - } - - bool ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock) - { - // Open history file to read - CAutoFile filein = CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); - if (!filein) - return error("CBlockUndo::ReadFromDisk : OpenBlockFile failed"); - - // Read block - uint256 hashChecksum; - try { - filein >> *this; - filein >> hashChecksum; - } - catch (std::exception &e) { - return error("%s : Deserialize or I/O error - %s", __func__, e.what()); - } - - // Verify checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - hasher << hashBlock; - hasher << *this; - if (hashChecksum != hasher.GetHash()) - return error("CBlockUndo::ReadFromDisk : Checksum mismatch"); - - return true; - } + bool WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock); + bool ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock); }; @@ -385,7 +328,7 @@ private: int nHashType; public: - CScriptCheck() {} + CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), nHashType(0) {} CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, int nHashTypeIn) : scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), nHashType(nHashTypeIn) { } @@ -625,9 +568,7 @@ public: SetNull(); } - std::string ToString() const { - return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst).c_str(), DateTimeStrFormat("%Y-%m-%d", nTimeLast).c_str()); - } + std::string ToString() const; // update statistics (does not update nSize) void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) { @@ -794,17 +735,7 @@ public: uint256 GetBlockWork() const { - uint256 bnTarget; - bool fNegative; - bool fOverflow; - bnTarget.SetCompact(nBits, &fNegative, &fOverflow); - if (fNegative || fOverflow || bnTarget == 0) - return 0; - // 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; + return GetProofIncrement(nBits); } enum { nMedianTimeSpan=11 }; @@ -839,11 +770,6 @@ public: GetBlockHash().ToString()); } - void print() const - { - 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 { @@ -935,11 +861,6 @@ public: hashPrev.ToString()); return str; } - - void print() const - { - LogPrintf("%s\n", ToString()); - } }; /** Capture information about block/transaction validation */ @@ -955,7 +876,7 @@ private: unsigned char chRejectCode; bool corruptionPossible; public: - CValidationState() : mode(MODE_VALID), nDoS(0), corruptionPossible(false) {} + CValidationState() : mode(MODE_VALID), nDoS(0), chRejectCode(0), corruptionPossible(false) {} bool DoS(int level, bool ret = false, unsigned char chRejectCodeIn=0, std::string strRejectReasonIn="", bool corruptionIn=false) { diff --git a/src/miner.cpp b/src/miner.cpp index 9408d2c5aa..96dc80a26d 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -3,8 +3,6 @@ // 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" @@ -12,10 +10,14 @@ #include "main.h" #include "net.h" #include "pow.h" +#include "util.h" +#include "utilmoneystr.h" #ifdef ENABLE_WALLET #include "wallet.h" #endif +#include <boost/thread.hpp> + using namespace std; ////////////////////////////////////////////////////////////////////////////// @@ -42,14 +44,6 @@ public: COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0) { } - - void print() const - { - 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; @@ -313,7 +307,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - UpdateTime(*pblock, pindexPrev); + UpdateTime(pblock, pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); @@ -404,7 +398,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { - pblock->print(); + LogPrintf("%s\n", pblock->ToString()); LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue)); // Found a solution @@ -546,7 +540,7 @@ void static BitcoinMiner(CWallet *pwallet) break; // Update nTime every few seconds - UpdateTime(*pblock, pindexPrev); + UpdateTime(pblock, pindexPrev); if (Params().AllowMinDifficultyBlocks()) { // Changing pblock->nTime can change work required on testnet: diff --git a/src/net.cpp b/src/net.cpp index ec58f84b06..3966706207 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -28,6 +28,7 @@ #endif #include <boost/filesystem.hpp> +#include <boost/thread.hpp> // Dump addresses to peers.dat every 15 minutes (900s) #define DUMP_ADDRESSES_INTERVAL 900 @@ -307,12 +308,18 @@ bool IsLocal(const CService& addr) return mapLocalHost.count(addr) > 0; } +/** check whether a given network is one we can probably connect to */ +bool IsReachable(enum Network net) +{ + LOCK(cs_mapLocalHost); + return vfReachable[net] && !vfLimited[net]; +} + /** check whether a given address is in a network we can probably connect to */ bool IsReachable(const CNetAddr& addr) { - LOCK(cs_mapLocalHost); enum Network net = addr.GetNetwork(); - return vfReachable[net] && !vfLimited[net]; + return IsReachable(net); } bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet) @@ -2031,3 +2038,157 @@ bool CAddrDB::Read(CAddrMan& addr) return true; } + +unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } +unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } + +CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000) +{ + nServices = 0; + hSocket = hSocketIn; + nRecvVersion = INIT_PROTO_VERSION; + nLastSend = 0; + nLastRecv = 0; + nSendBytes = 0; + nRecvBytes = 0; + nTimeConnected = GetTime(); + addr = addrIn; + addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; + nVersion = 0; + strSubVer = ""; + fWhitelisted = false; + fOneShot = false; + fClient = false; // set by version message + fInbound = fInboundIn; + fNetworkNode = false; + fSuccessfullyConnected = false; + fDisconnect = false; + nRefCount = 0; + nSendSize = 0; + nSendOffset = 0; + hashContinue = 0; + pindexLastGetBlocksBegin = 0; + hashLastGetBlocksEnd = 0; + nStartingHeight = -1; + fStartSync = false; + fGetAddr = false; + fRelayTxes = false; + setInventoryKnown.max_size(SendBufferSize() / 1000); + pfilter = new CBloomFilter(); + nPingNonceSent = 0; + nPingUsecStart = 0; + nPingUsecTime = 0; + fPingQueued = false; + + { + LOCK(cs_nLastNodeId); + 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(); + + GetNodeSignals().InitializeNode(GetId(), this); +} + +CNode::~CNode() +{ + CloseSocket(hSocket); + + if (pfilter) + delete pfilter; + + GetNodeSignals().FinalizeNode(GetId()); +} + +void CNode::AskFor(const CInv& inv) +{ + // We're using mapAskFor as a priority queue, + // the key is the earliest time the request can be sent + int64_t nRequestTime; + limitedmap<CInv, int64_t>::const_iterator it = mapAlreadyAskedFor.find(inv); + if (it != mapAlreadyAskedFor.end()) + nRequestTime = it->second; + else + nRequestTime = 0; + 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; + static int64_t nLastTime; + ++nLastTime; + nNow = std::max(nNow, nLastTime); + nLastTime = nNow; + + // Each retry is 2 minutes after the last + nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow); + if (it != mapAlreadyAskedFor.end()) + mapAlreadyAskedFor.update(it, nRequestTime); + else + mapAlreadyAskedFor.insert(std::make_pair(inv, nRequestTime)); + mapAskFor.insert(std::make_pair(nRequestTime, inv)); +} + +void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend) +{ + ENTER_CRITICAL_SECTION(cs_vSend); + assert(ssSend.size() == 0); + ssSend << CMessageHeader(pszCommand, 0); + LogPrint("net", "sending: %s ", pszCommand); +} + +void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend) +{ + ssSend.clear(); + + LEAVE_CRITICAL_SECTION(cs_vSend); + + LogPrint("net", "(aborted)\n"); +} + +void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend) +{ + // The -*messagestest options are intentionally not documented in the help message, + // since they are only used during development to debug the networking code and are + // not intended for end-users. + if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0) + { + LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n"); + AbortMessage(); + return; + } + if (mapArgs.count("-fuzzmessagestest")) + Fuzz(GetArg("-fuzzmessagestest", 10)); + + if (ssSend.size() == 0) + return; + + // Set the size + unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; + memcpy((char*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], &nSize, sizeof(nSize)); + + // Set the checksum + uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end()); + unsigned int nChecksum = 0; + memcpy(&nChecksum, &hash, sizeof(nChecksum)); + assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum)); + memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum)); + + LogPrint("net", "(%d bytes) peer=%d\n", nSize, id); + + std::deque<CSerializeData>::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData()); + ssSend.GetAndClear(*it); + nSendSize += (*it).size(); + + // If write queue empty, attempt "optimistic write" + if (it == vSendMsg.begin()) + SocketSendData(this); + + LEAVE_CRITICAL_SECTION(cs_vSend); +} @@ -16,7 +16,7 @@ #include "random.h" #include "sync.h" #include "uint256.h" -#include "util.h" +#include "utilstrencodings.h" #include <deque> #include <stdint.h> @@ -25,6 +25,7 @@ #include <arpa/inet.h> #endif +#include <boost/filesystem/path.hpp> #include <boost/foreach.hpp> #include <boost/signals2/signal.hpp> @@ -51,8 +52,8 @@ static const bool DEFAULT_UPNP = USE_UPNP; 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); } +unsigned int ReceiveFloodSize(); +unsigned int SendBufferSize(); void AddOneShot(std::string strDest); bool RecvLine(SOCKET hSocket, std::string& strLine); @@ -106,6 +107,7 @@ bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE); bool SeenLocal(const CService& addr); bool IsLocal(const CService& addr); bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL); +bool IsReachable(enum Network net); bool IsReachable(const CNetAddr &addr); void SetReachable(enum Network net, bool fFlag = true); CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); @@ -299,70 +301,8 @@ public: // Whether a ping is requested. bool fPingQueued; - CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000) - { - nServices = 0; - hSocket = hSocketIn; - nRecvVersion = INIT_PROTO_VERSION; - nLastSend = 0; - nLastRecv = 0; - nSendBytes = 0; - nRecvBytes = 0; - nTimeConnected = GetTime(); - addr = addrIn; - addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; - nVersion = 0; - strSubVer = ""; - fWhitelisted = false; - fOneShot = false; - fClient = false; // set by version message - fInbound = fInboundIn; - fNetworkNode = false; - fSuccessfullyConnected = false; - fDisconnect = false; - nRefCount = 0; - nSendSize = 0; - nSendOffset = 0; - hashContinue = 0; - pindexLastGetBlocksBegin = 0; - hashLastGetBlocksEnd = 0; - nStartingHeight = -1; - fStartSync = false; - fGetAddr = false; - fRelayTxes = false; - setInventoryKnown.max_size(SendBufferSize() / 1000); - pfilter = new CBloomFilter(); - nPingNonceSent = 0; - nPingUsecStart = 0; - nPingUsecTime = 0; - fPingQueued = false; - - { - LOCK(cs_nLastNodeId); - 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(); - - GetNodeSignals().InitializeNode(GetId(), this); - } - - ~CNode() - { - CloseSocket(hSocket); - - if (pfilter) - delete pfilter; - - GetNodeSignals().FinalizeNode(GetId()); - } + CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false); + ~CNode(); private: // Network usage totals @@ -451,96 +391,16 @@ public: } } - void AskFor(const CInv& inv) - { - // We're using mapAskFor as a priority queue, - // the key is the earliest time the request can be sent - int64_t nRequestTime; - limitedmap<CInv, int64_t>::const_iterator it = mapAlreadyAskedFor.find(inv); - if (it != mapAlreadyAskedFor.end()) - nRequestTime = it->second; - else - nRequestTime = 0; - 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; - static int64_t nLastTime; - ++nLastTime; - nNow = std::max(nNow, nLastTime); - nLastTime = nNow; - - // Each retry is 2 minutes after the last - nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow); - if (it != mapAlreadyAskedFor.end()) - mapAlreadyAskedFor.update(it, nRequestTime); - else - mapAlreadyAskedFor.insert(std::make_pair(inv, nRequestTime)); - mapAskFor.insert(std::make_pair(nRequestTime, inv)); - } - - + void AskFor(const CInv& inv); // TODO: Document the postcondition of this function. Is cs_vSend locked? - void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend) - { - ENTER_CRITICAL_SECTION(cs_vSend); - assert(ssSend.size() == 0); - ssSend << CMessageHeader(pszCommand, 0); - LogPrint("net", "sending: %s ", pszCommand); - } + void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend); // TODO: Document the precondition of this function. Is cs_vSend locked? - void AbortMessage() UNLOCK_FUNCTION(cs_vSend) - { - ssSend.clear(); - - LEAVE_CRITICAL_SECTION(cs_vSend); - - LogPrint("net", "(aborted)\n"); - } + void AbortMessage() UNLOCK_FUNCTION(cs_vSend); // TODO: Document the precondition of this function. Is cs_vSend locked? - void EndMessage() UNLOCK_FUNCTION(cs_vSend) - { - // The -*messagestest options are intentionally not documented in the help message, - // since they are only used during development to debug the networking code and are - // not intended for end-users. - if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0) - { - LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n"); - AbortMessage(); - return; - } - if (mapArgs.count("-fuzzmessagestest")) - Fuzz(GetArg("-fuzzmessagestest", 10)); - - if (ssSend.size() == 0) - return; - - // Set the size - unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; - memcpy((char*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], &nSize, sizeof(nSize)); - - // Set the checksum - uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end()); - unsigned int nChecksum = 0; - memcpy(&nChecksum, &hash, sizeof(nChecksum)); - assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum)); - memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum)); - - LogPrint("net", "(%d bytes) peer=%d\n", nSize, id); - - std::deque<CSerializeData>::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData()); - ssSend.GetAndClear(*it); - nSendSize += (*it).size(); - - // If write queue empty, attempt "optimistic write" - if (it == vSendMsg.begin()) - SocketSendData(this); - - LEAVE_CRITICAL_SECTION(cs_vSend); - } + void EndMessage() UNLOCK_FUNCTION(cs_vSend); void PushVersion(); diff --git a/src/netbase.cpp b/src/netbase.cpp index 1031e7e38a..d5821d4465 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -13,6 +13,7 @@ #include "sync.h" #include "uint256.h" #include "util.h" +#include "utilstrencodings.h" #ifdef HAVE_GETADDRINFO_A #include <netdb.h> @@ -27,6 +28,7 @@ #include <boost/algorithm/string/case_conv.hpp> // for to_lower() #include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith() +#include <boost/thread.hpp> #if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) #define MSG_NOSIGNAL 0 @@ -47,10 +49,20 @@ enum Network ParseNetwork(std::string net) { boost::to_lower(net); if (net == "ipv4") return NET_IPV4; if (net == "ipv6") return NET_IPV6; - if (net == "tor") return NET_TOR; + if (net == "tor" || net == "onion") return NET_TOR; return NET_UNROUTABLE; } +std::string GetNetworkName(enum Network net) { + switch(net) + { + case NET_IPV4: return "ipv4"; + case NET_IPV6: return "ipv6"; + case NET_TOR: return "onion"; + default: return ""; + } +} + void SplitHostPort(std::string in, int &portOut, std::string &hostOut) { size_t colon = in.find_last_of(':'); // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator @@ -864,11 +876,6 @@ uint64_t CNetAddr::GetHash() const return nRet; } -void CNetAddr::print() const -{ - LogPrintf("CNetAddr(%s)\n", ToString()); -} - // private extensions to enum Network, only returned by GetExtNetwork, // and only used in GetReachabilityFrom static const int NET_UNKNOWN = NET_MAX + 0; @@ -1097,11 +1104,6 @@ std::string CService::ToString() const return ToStringIPPort(); } -void CService::print() const -{ - LogPrintf("CService(%s)\n", ToString()); -} - void CService::SetPort(unsigned short portIn) { port = portIn; diff --git a/src/netbase.h b/src/netbase.h index 7d83e35344..2df3c4474d 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -26,7 +26,7 @@ extern bool fNameLookup; enum Network { - NET_UNROUTABLE, + NET_UNROUTABLE = 0, NET_IPV4, NET_IPV6, NET_TOR, @@ -80,7 +80,6 @@ class CNetAddr bool GetInAddr(struct in_addr* pipv4Addr) const; std::vector<unsigned char> GetGroup() const; int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const; - void print() const; CNetAddr(const struct in6_addr& pipv6Addr); bool GetIn6Addr(struct in6_addr* pipv6Addr) const; @@ -145,7 +144,6 @@ class CService : public CNetAddr std::string ToString() const; std::string ToStringPort() const; std::string ToStringIPPort() const; - void print() const; CService(const struct in6_addr& ipv6Addr, unsigned short port); CService(const struct sockaddr_in6& addr); @@ -164,6 +162,7 @@ class CService : public CNetAddr typedef CService proxyType; enum Network ParseNetwork(std::string net); +std::string GetNetworkName(enum Network net); void SplitHostPort(std::string in, int &portOut, std::string &hostOut); bool SetProxy(enum Network net, CService addrProxy); bool GetProxy(enum Network net, proxyType &proxyInfoOut); diff --git a/src/noui.cpp b/src/noui.cpp index 32c861b0d9..8b00fd4057 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -8,6 +8,7 @@ #include "ui_interface.h" #include "util.h" +#include <cstdio> #include <stdint.h> #include <string> diff --git a/src/pow.cpp b/src/pow.cpp index c0d0a7ca20..893f6c18be 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -8,7 +8,9 @@ #include "chainparams.h" #include "core.h" #include "main.h" +#include "timedata.h" #include "uint256.h" +#include "util.h" unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock) { @@ -93,27 +95,58 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits) } // -// minimum amount of work that could possibly be required nTime after -// minimum work required was nBase +// true if nBits is greater than the minimum amount of work that could +// possibly be required deltaTime after minimum work required was nBase // -unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime) +bool CheckMinWork(unsigned int nBits, unsigned int nBase, int64_t deltaTime) { + bool fOverflow = false; + uint256 bnNewBlock; + bnNewBlock.SetCompact(nBits, NULL, &fOverflow); + if (fOverflow) + return false; + 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(); + if (Params().AllowMinDifficultyBlocks() && deltaTime > Params().TargetSpacing()*2) + return bnNewBlock <= bnLimit; uint256 bnResult; bnResult.SetCompact(nBase); - while (nTime > 0 && bnResult < bnLimit) + while (deltaTime > 0 && bnResult < bnLimit) { // Maximum 400% adjustment... bnResult *= 4; // ... in best-case exactly 4-times-normal target time - nTime -= Params().TargetTimespan()*4; + deltaTime -= Params().TargetTimespan()*4; } if (bnResult > bnLimit) bnResult = bnLimit; - return bnResult.GetCompact(); + + return bnNewBlock <= bnResult; +} + +void UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev) +{ + pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + + // Updating time can change work required on testnet: + if (Params().AllowMinDifficultyBlocks()) + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); +} + +uint256 GetProofIncrement(unsigned int nBits) +{ + uint256 bnTarget; + bool fNegative; + bool fOverflow; + bnTarget.SetCompact(nBits, &fNegative, &fOverflow); + if (fNegative || fOverflow || bnTarget == 0) + return 0; + // 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; } @@ -17,7 +17,11 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits); -/** Calculate the minimum amount of work a received block needs, without knowing its direct parent */ -unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime); +/** Check the work is more than the minimum a received block needs, without knowing its direct parent */ +bool CheckMinWork(unsigned int nBits, unsigned int nBase, int64_t deltaTime); + +void UpdateTime(CBlockHeader* block, const CBlockIndex* pindexPrev); + +uint256 GetProofIncrement(unsigned int nBits); #endif diff --git a/src/protocol.cpp b/src/protocol.cpp index 87b2f23873..341de0602a 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -144,9 +144,3 @@ std::string CInv::ToString() const { return strprintf("%s %s", GetCommand(), hash.ToString()); } - -void CInv::print() const -{ - LogPrintf("CInv(%s)\n", ToString()); -} - diff --git a/src/protocol.h b/src/protocol.h index 1f23274299..d7565584af 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -98,8 +98,6 @@ class CAddress : public CService READWRITE(*pip); ) - void print() const; - // TODO: make private (improves encapsulation) public: uint64_t nServices; @@ -130,7 +128,6 @@ class CInv bool IsKnownType() const; const char* GetCommand() const; std::string ToString() const; - void print() const; // TODO: make private (improves encapsulation) public: diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index a43e7cb756..6cc6b99ceb 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -33,6 +33,7 @@ #include <stdint.h> #include <boost/filesystem/operations.hpp> +#include <boost/thread.hpp> #include <QApplication> #include <QDebug> #include <QLibraryInfo> @@ -414,8 +415,8 @@ void BitcoinApplication::initializeResult(int retval) { walletModel = new WalletModel(pwalletMain, optionsModel); - window->addWallet("~Default", walletModel); - window->setCurrentWallet("~Default"); + window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel); + window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET); connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)), paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray))); diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index 6dba62035b..42bb091e25 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -17,6 +17,9 @@ <file alias="transaction_3">res/icons/clock3.png</file> <file alias="transaction_4">res/icons/clock4.png</file> <file alias="transaction_5">res/icons/clock5.png</file> + <file alias="eye">res/icons/eye.png</file> + <file alias="eye_minus">res/icons/eye_minus.png</file> + <file alias="eye_plus">res/icons/eye_plus.png</file> <file alias="options">res/icons/configure.png</file> <file alias="receiving_addresses">res/icons/receive.png</file> <file alias="editpaste">res/icons/editpaste.png</file> diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index bfca5e8d1a..790301a1eb 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -24,6 +24,7 @@ #endif #include "init.h" +#include "util.h" #include "ui_interface.h" #include <iostream> @@ -61,10 +62,35 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) : QMainWindow(parent), clientModel(0), walletFrame(0), + unitDisplayControl(0), + labelEncryptionIcon(0), + labelConnectionsIcon(0), + labelBlocksIcon(0), + progressBarLabel(0), + progressBar(0), + progressDialog(0), + appMenuBar(0), + overviewAction(0), + historyAction(0), + quitAction(0), + sendCoinsAction(0), + usedSendingAddressesAction(0), + usedReceivingAddressesAction(0), + signMessageAction(0), + verifyMessageAction(0), + aboutAction(0), + receiveCoinsAction(0), + optionsAction(0), + toggleHideAction(0), encryptWalletAction(0), + backupWalletAction(0), changePassphraseAction(0), aboutQtAction(0), + openRPCConsoleAction(0), + openAction(0), + showHelpMessageAction(0), trayIcon(0), + trayIconMenu(0), notificator(0), rpcConsole(0), prevBlocks(0), @@ -425,8 +451,15 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) walletFrame->setClientModel(clientModel); } #endif - - this->unitDisplayControl->setOptionsModel(clientModel->getOptionsModel()); + unitDisplayControl->setOptionsModel(clientModel->getOptionsModel()); + } else { + // Disable possibility to show main window via action + toggleHideAction->setEnabled(false); + if(trayIconMenu) + { + // Disable context menu on tray icon + trayIconMenu->clear(); + } } } @@ -495,7 +528,6 @@ void BitcoinGUI::createTrayIcon(bool fIsTestnet) void BitcoinGUI::createTrayIconMenu() { - QMenu *trayIconMenu; #ifndef Q_OS_MAC // return if trayIcon is unset (only on non-Mac OSes) if (!trayIcon) @@ -536,7 +568,7 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) if(reason == QSystemTrayIcon::Trigger) { // Click on system tray icon triggers show/hide of the main window - toggleHideAction->trigger(); + toggleHidden(); } } #endif @@ -922,6 +954,7 @@ void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) { if(!clientModel) return; + // activateWindow() (sometimes) helps with keyboard focus on Windows if (isHidden()) { @@ -1006,9 +1039,10 @@ void BitcoinGUI::unsubscribeFromCoreSignals() uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3)); } -UnitDisplayStatusBarControl::UnitDisplayStatusBarControl():QLabel() +UnitDisplayStatusBarControl::UnitDisplayStatusBarControl() : + optionsModel(0), + menu(0) { - optionsModel = 0; createContextMenu(); setToolTip(tr("Unit to show amounts in. Click to select another unit.")); } @@ -1068,4 +1102,3 @@ void UnitDisplayStatusBarControl::onMenuSelection(QAction* action) optionsModel->setDisplayUnit(action->data()); } } - diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 30dd7ae317..30b05cb7d9 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -103,6 +103,7 @@ private: QAction *showHelpMessageAction; QSystemTrayIcon *trayIcon; + QMenu *trayIconMenu; Notificator *notificator; RPCConsole *rpcConsole; @@ -219,6 +220,7 @@ protected: 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. */ diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index fea99bfd93..738fb48ef8 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -13,6 +13,7 @@ #include "main.h" #include "net.h" #include "ui_interface.h" +#include "util.h" #include <stdint.h> diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index 7784a862d7..53d416ef38 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -13,8 +13,8 @@ <property name="windowTitle"> <string>Form</string> </property> - <layout class="QFormLayout" name="formLayout_3"> - <item row="0" column="0" colspan="2"> + <layout class="QVBoxLayout" name="topLayout"> + <item> <widget class="QLabel" name="labelAlerts"> <property name="visible"> <bool>false</bool> @@ -30,7 +30,7 @@ </property> </widget> </item> - <item row="1" column="1"> + <item> <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1"> <item> <layout class="QVBoxLayout" name="verticalLayout_2"> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 389a08d9e8..304177ee11 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -810,7 +810,7 @@ QString formatDurationStr(int secs) return strList.join(" "); } -QString formatServicesStr(uint64_t mask) +QString formatServicesStr(quint64 mask) { QStringList strList; diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 0ae5154d4b..67e11e59a0 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -180,7 +180,7 @@ namespace GUIUtil QString formatDurationStr(int secs); /* Format CNodeStats.nServices bitmask into a user-readable string */ - QString formatServicesStr(uint64_t mask); + QString formatServicesStr(quint64 mask); /* Format a CNodeCombinedStats.dPingTime into a user-readable string or display N/A, if 0*/ QString formatPingTime(double dPingTime); diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index fd1d446f9b..c775a7f8d6 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -21,6 +21,7 @@ #include "wallet.h" // for CWallet::minTxFee #endif +#include <boost/thread.hpp> #include <QDir> #include <QIntValidator> #include <QLocale> diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index b5a3de48ca..15501b8a8a 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -57,7 +57,15 @@ public: } painter->setPen(foreground); - painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address); + QRect boundingRect; + painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address, &boundingRect); + + if (index.data(TransactionTableModel::WatchonlyRole).toBool()) + { + QIcon iconWatchonly = qvariant_cast<QIcon>(index.data(TransactionTableModel::WatchonlyDecorationRole)); + QRect watchonlyRect(boundingRect.right() + 5, mainRect.top()+ypad+halfheight, 16, halfheight); + iconWatchonly.paint(painter, watchonlyRect); + } if(amount < 0) { @@ -160,18 +168,25 @@ void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 // for the non-mining users bool showImmature = immatureBalance != 0; bool showWatchOnlyImmature = watchImmatureBalance != 0; - bool showWatchOnly = (watchOnlyBalance != 0 || watchUnconfBalance != 0 || showWatchOnlyImmature); // for symmetry reasons also show immature label when the watch-only one is shown ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature); ui->labelImmatureText->setVisible(showImmature || showWatchOnlyImmature); - ui->labelSpendable->setVisible(showWatchOnly); // show spendable label (only when watch-only is active) - ui->labelWatchonly->setVisible(showWatchOnly); // show watch-only label - ui->lineWatchBalance->setVisible(showWatchOnly); // show watch-only balance separator line - ui->labelWatchAvailable->setVisible(showWatchOnly); // show watch-only available balance ui->labelWatchImmature->setVisible(showWatchOnlyImmature); // show watch-only immature balance - ui->labelWatchPending->setVisible(showWatchOnly); // show watch-only pending balance - ui->labelWatchTotal->setVisible(showWatchOnly); // show watch-only total balance +} + +// show/hide watch-only labels +void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly) +{ + ui->labelSpendable->setVisible(showWatchOnly); // show spendable label (only when watch-only is active) + ui->labelWatchonly->setVisible(showWatchOnly); // show watch-only label + ui->lineWatchBalance->setVisible(showWatchOnly); // show watch-only balance separator line + ui->labelWatchAvailable->setVisible(showWatchOnly); // show watch-only available balance + ui->labelWatchPending->setVisible(showWatchOnly); // show watch-only pending balance + ui->labelWatchTotal->setVisible(showWatchOnly); // show watch-only total balance + + if (!showWatchOnly) + ui->labelWatchImmature->hide(); } void OverviewPage::setClientModel(ClientModel *model) @@ -208,6 +223,9 @@ void OverviewPage::setWalletModel(WalletModel *model) 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())); + + updateWatchOnlyLabels(model->haveWatchOnly()); + connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyLabels(bool))); } // update the display unit, to not use the default ("BTC") diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index fe00106770..f46374efba 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -58,6 +58,7 @@ private slots: void updateDisplayUnit(); void handleTransactionClicked(const QModelIndex &index); void updateAlerts(const QString &warnings); + void updateWatchOnlyLabels(bool showWatchOnly); }; #endif // OVERVIEWPAGE_H diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index a9f1566d62..f6a4b599de 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -11,6 +11,7 @@ #include "base58.h" #include "ui_interface.h" +#include "util.h" #include "wallet.h" #include <cstdlib> diff --git a/src/qt/res/icons/eye.png b/src/qt/res/icons/eye.png Binary files differnew file mode 100644 index 0000000000..c4d182adbf --- /dev/null +++ b/src/qt/res/icons/eye.png diff --git a/src/qt/res/icons/eye_minus.png b/src/qt/res/icons/eye_minus.png Binary files differnew file mode 100644 index 0000000000..08b048eae3 --- /dev/null +++ b/src/qt/res/icons/eye_minus.png diff --git a/src/qt/res/icons/eye_plus.png b/src/qt/res/icons/eye_plus.png Binary files differnew file mode 100644 index 0000000000..4ad653156f --- /dev/null +++ b/src/qt/res/icons/eye_plus.png diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 1162e2d87f..5dd110b36a 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -4,6 +4,7 @@ #include "splashscreen.h" +#include "version.h" #include "clientversion.h" #include "init.h" #include "ui_interface.h" diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 4f6e3169f5..8258e719a3 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -15,6 +15,7 @@ #include "transactionrecord.h" #include "timedata.h" #include "ui_interface.h" +#include "util.h" #include "wallet.h" #include <stdint.h> diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index f9546fddb5..6ab029173b 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -22,6 +22,7 @@ TransactionFilterProxy::TransactionFilterProxy(QObject *parent) : dateTo(MAX_DATE), addrPrefix(), typeFilter(ALL_TYPES), + watchOnlyFilter(WatchOnlyFilter_All), minAmount(0), limitRows(-1), showInactive(true) @@ -34,6 +35,7 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex & int type = index.data(TransactionTableModel::TypeRole).toInt(); QDateTime datetime = index.data(TransactionTableModel::DateRole).toDateTime(); + bool involvesWatchAddress = index.data(TransactionTableModel::WatchonlyRole).toBool(); QString address = index.data(TransactionTableModel::AddressRole).toString(); QString label = index.data(TransactionTableModel::LabelRole).toString(); qint64 amount = llabs(index.data(TransactionTableModel::AmountRole).toLongLong()); @@ -43,6 +45,10 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex & return false; if(!(TYPE(type) & typeFilter)) return false; + if (involvesWatchAddress && watchOnlyFilter == WatchOnlyFilter_No) + return false; + if (!involvesWatchAddress && watchOnlyFilter == WatchOnlyFilter_Yes) + return false; if(datetime < dateFrom || datetime > dateTo) return false; if (!address.contains(addrPrefix, Qt::CaseInsensitive) && !label.contains(addrPrefix, Qt::CaseInsensitive)) @@ -78,6 +84,12 @@ void TransactionFilterProxy::setMinAmount(qint64 minimum) invalidateFilter(); } +void TransactionFilterProxy::setWatchOnlyFilter(WatchOnlyFilter filter) +{ + this->watchOnlyFilter = filter; + invalidateFilter(); +} + void TransactionFilterProxy::setLimit(int limit) { this->limitRows = limit; diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index 9919bc3fd6..f408317b53 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -25,6 +25,13 @@ public: static quint32 TYPE(int type) { return 1<<type; } + enum WatchOnlyFilter + { + WatchOnlyFilter_All, + WatchOnlyFilter_Yes, + WatchOnlyFilter_No + }; + void setDateRange(const QDateTime &from, const QDateTime &to); void setAddressPrefix(const QString &addrPrefix); /** @@ -32,6 +39,7 @@ public: */ void setTypeFilter(quint32 modes); void setMinAmount(qint64 minimum); + void setWatchOnlyFilter(WatchOnlyFilter filter); /** Set maximum number of rows returned, -1 if unlimited. */ void setLimit(int limit); @@ -49,6 +57,7 @@ private: QDateTime dateTo; QString addrPrefix; quint32 typeFilter; + WatchOnlyFilter watchOnlyFilter; qint64 minAmount; int limitRows; bool showInactive; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 1647bc776f..1a1f726bf8 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -27,6 +27,7 @@ // Amount column is right-aligned it contains numbers static int column_alignments[] = { Qt::AlignLeft|Qt::AlignVCenter, /* status */ + Qt::AlignLeft|Qt::AlignVCenter, /* watchonly */ Qt::AlignLeft|Qt::AlignVCenter, /* date */ Qt::AlignLeft|Qt::AlignVCenter, /* type */ Qt::AlignLeft|Qt::AlignVCenter, /* address */ @@ -234,7 +235,7 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren walletModel(parent), priv(new TransactionTablePriv(wallet, this)) { - columns << QString() << tr("Date") << tr("Type") << tr("Address") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); + columns << QString() << QString() << tr("Date") << tr("Type") << tr("Address") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); priv->refreshWallet(); connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); @@ -393,22 +394,19 @@ 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) + watchAddress; + return QString::fromStdString(wtx->address); case TransactionRecord::RecvWithAddress: case TransactionRecord::SendToAddress: case TransactionRecord::Generated: - return lookupAddress(wtx->address, tooltip) + watchAddress; + return lookupAddress(wtx->address, tooltip); case TransactionRecord::SendToOther: - return QString::fromStdString(wtx->address) + watchAddress; + return QString::fromStdString(wtx->address); case TransactionRecord::SendToSelf: default: - return tr("(n/a)") + watchAddress; + return tr("(n/a)"); } } @@ -482,6 +480,14 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) return QColor(0,0,0); } +QVariant TransactionTableModel::txWatchonlyDecoration(const TransactionRecord *wtx) const +{ + if (wtx->involvesWatchAddress) + return QIcon(":/icons/eye"); + else + return QVariant(); +} + QString TransactionTableModel::formatTooltip(const TransactionRecord *rec) const { QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec); @@ -506,6 +512,8 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const { case Status: return txStatusDecoration(rec); + case Watchonly: + return txWatchonlyDecoration(rec); case ToAddress: return txAddressDecoration(rec); } @@ -533,6 +541,8 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const return rec->time; case Type: return formatTxType(rec); + case Watchonly: + return (rec->involvesWatchAddress ? 1 : 0); case ToAddress: return formatTxToAddress(rec, true); case Amount: @@ -562,6 +572,10 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const return rec->type; case DateRole: return QDateTime::fromTime_t(static_cast<uint>(rec->time)); + case WatchonlyRole: + return rec->involvesWatchAddress; + case WatchonlyDecorationRole: + return txWatchonlyDecoration(rec); case LongDescriptionRole: return priv->describe(rec, walletModel->getOptionsModel()->getDisplayUnit()); case AddressRole: @@ -606,6 +620,8 @@ QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientat return tr("Date and time that the transaction was received."); case Type: return tr("Type of transaction."); + case Watchonly: + return tr("Whether or not a watch-only address is involved in this transaction."); case ToAddress: return tr("Destination address of transaction."); case Amount: diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index 2124d3dd1c..413f3f9bf1 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -28,10 +28,11 @@ public: enum ColumnIndex { Status = 0, - Date = 1, - Type = 2, - ToAddress = 3, - Amount = 4 + Watchonly = 1, + Date = 2, + Type = 3, + ToAddress = 4, + Amount = 5 }; /** Roles to get specific information from a transaction row. @@ -42,6 +43,10 @@ public: TypeRole = Qt::UserRole, /** Date and time this transaction was created */ DateRole, + /** Watch-only boolean */ + WatchonlyRole, + /** Watch-only icon */ + WatchonlyDecorationRole, /** Long description (HTML format) */ LongDescriptionRole, /** Address of transaction */ @@ -83,6 +88,7 @@ private: QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true, BitcoinUnits::SeparatorStyle separators=BitcoinUnits::separatorStandard) const; QString formatTooltip(const TransactionRecord *rec) const; QVariant txStatusDecoration(const TransactionRecord *wtx) const; + QVariant txWatchonlyDecoration(const TransactionRecord *wtx) const; QVariant txAddressDecoration(const TransactionRecord *wtx) const; public slots: diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 7e8b71d8ea..2d34d58129 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -51,6 +51,13 @@ TransactionView::TransactionView(QWidget *parent) : hlayout->addSpacing(23); #endif + watchOnlyWidget = new QComboBox(this); + watchOnlyWidget->setFixedWidth(24); + watchOnlyWidget->addItem("", TransactionFilterProxy::WatchOnlyFilter_All); + watchOnlyWidget->addItem(QIcon(":/icons/eye_plus"), "", TransactionFilterProxy::WatchOnlyFilter_Yes); + watchOnlyWidget->addItem(QIcon(":/icons/eye_minus"), "", TransactionFilterProxy::WatchOnlyFilter_No); + hlayout->addWidget(watchOnlyWidget); + dateWidget = new QComboBox(this); #ifdef Q_OS_MAC dateWidget->setFixedWidth(121); @@ -150,6 +157,7 @@ TransactionView::TransactionView(QWidget *parent) : connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int))); connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int))); + connect(watchOnlyWidget, SIGNAL(activated(int)), this, SLOT(chooseWatchonly(int))); connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString))); connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString))); @@ -187,6 +195,7 @@ void TransactionView::setModel(WalletModel *model) transactionView->verticalHeader()->hide(); transactionView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH); + transactionView->setColumnWidth(TransactionTableModel::Watchonly, WATCHONLY_COLUMN_WIDTH); transactionView->setColumnWidth(TransactionTableModel::Date, DATE_COLUMN_WIDTH); transactionView->setColumnWidth(TransactionTableModel::Type, TYPE_COLUMN_WIDTH); transactionView->setColumnWidth(TransactionTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH); @@ -211,6 +220,12 @@ void TransactionView::setModel(WalletModel *model) } } } + + // show/hide column Watch-only + updateWatchOnlyColumn(model->haveWatchOnly()); + + // Watch-only signal + connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool))); } } @@ -270,6 +285,14 @@ void TransactionView::chooseType(int idx) typeWidget->itemData(idx).toInt()); } +void TransactionView::chooseWatchonly(int idx) +{ + if(!transactionProxyModel) + return; + transactionProxyModel->setWatchOnlyFilter( + (TransactionFilterProxy::WatchOnlyFilter)watchOnlyWidget->itemData(idx).toInt()); +} + void TransactionView::changedPrefix(const QString &prefix) { if(!transactionProxyModel) @@ -307,6 +330,8 @@ void TransactionView::exportClicked() // name, column, role writer.setModel(transactionProxyModel); writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole); + if (model && model->haveWatchOnly()) + writer.addColumn(tr("Watchonly"), TransactionTableModel::Watchonly); writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole); writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole); writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole); @@ -501,3 +526,10 @@ bool TransactionView::eventFilter(QObject *obj, QEvent *event) } return QWidget::eventFilter(obj, event); } + +// show/hide column Watch-only +void TransactionView::updateWatchOnlyColumn(bool fHaveWatchOnly) +{ + watchOnlyWidget->setVisible(fHaveWatchOnly); + transactionView->setColumnHidden(TransactionTableModel::Watchonly, !fHaveWatchOnly); +} diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 618efbc565..b249e00411 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -50,6 +50,7 @@ public: enum ColumnWidths { STATUS_COLUMN_WIDTH = 23, + WATCHONLY_COLUMN_WIDTH = 23, DATE_COLUMN_WIDTH = 120, TYPE_COLUMN_WIDTH = 120, AMOUNT_MINIMUM_COLUMN_WIDTH = 120, @@ -63,6 +64,7 @@ private: QComboBox *dateWidget; QComboBox *typeWidget; + QComboBox *watchOnlyWidget; QLineEdit *addressWidget; QLineEdit *amountWidget; @@ -91,6 +93,7 @@ private slots: void copyAmount(); void copyTxID(); void openThirdPartyTxUrl(QString url); + void updateWatchOnlyColumn(bool fHaveWatchOnly); signals: void doubleClicked(const QModelIndex&); @@ -101,6 +104,7 @@ signals: public slots: void chooseDate(int idx); void chooseType(int idx); + void chooseWatchonly(int idx); void changedPrefix(const QString &prefix); void changedAmount(const QString &amount); void exportClicked(); diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 5fb0da145d..7df9d1bc2d 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -10,9 +10,10 @@ #include "clientmodel.h" #include "guiutil.h" -#include "clientversion.h" #include "init.h" -#include "util.h" +#include "version.h" + +#include <stdio.h> #include <QLabel> #include <QRegExp> diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 0ad123f39d..92c22f5692 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -31,11 +31,11 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p transactionTableModel(0), recentRequestsTableModel(0), cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0), - cachedNumTransactions(0), cachedEncryptionStatus(Unencrypted), cachedNumBlocks(0) { fProcessingQueuedTransactions = false; + fHaveWatchOnly = wallet->HaveWatchOnly(); addressTableModel = new AddressTableModel(wallet, this); transactionTableModel = new TransactionTableModel(wallet, this); @@ -81,6 +81,11 @@ qint64 WalletModel::getImmatureBalance() const return wallet->GetImmatureBalance(); } +bool WalletModel::haveWatchOnly() const +{ + return fHaveWatchOnly; +} + qint64 WalletModel::getWatchBalance() const { return wallet->GetWatchOnlyBalance(); @@ -96,18 +101,6 @@ qint64 WalletModel::getWatchImmatureBalance() const return wallet->GetImmatureWatchOnlyBalance(); } -int WalletModel::getNumTransactions() const -{ - int numTransactions = 0; - { - LOCK(wallet->cs_wallet); - // the size of mapWallet contains the number of unique transaction IDs - // (e.g. payments to yourself generate 2 transactions, but both share the same transaction ID) - numTransactions = wallet->mapWallet.size(); - } - return numTransactions; -} - void WalletModel::updateStatus() { EncryptionStatus newEncryptionStatus = getEncryptionStatus(); @@ -144,9 +137,15 @@ void WalletModel::checkBalanceChanged() qint64 newBalance = getBalance(); qint64 newUnconfirmedBalance = getUnconfirmedBalance(); qint64 newImmatureBalance = getImmatureBalance(); - qint64 newWatchOnlyBalance = getWatchBalance(); - qint64 newWatchUnconfBalance = getWatchUnconfirmedBalance(); - qint64 newWatchImmatureBalance = getWatchImmatureBalance(); + qint64 newWatchOnlyBalance = 0; + qint64 newWatchUnconfBalance = 0; + qint64 newWatchImmatureBalance = 0; + if (haveWatchOnly()) + { + newWatchOnlyBalance = getWatchBalance(); + newWatchUnconfBalance = getWatchUnconfirmedBalance(); + newWatchImmatureBalance = getWatchImmatureBalance(); + } if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance || cachedWatchOnlyBalance != newWatchOnlyBalance || cachedWatchUnconfBalance != newWatchUnconfBalance || cachedWatchImmatureBalance != newWatchImmatureBalance) @@ -169,13 +168,6 @@ void WalletModel::updateTransaction(const QString &hash, int status) // Balance and number of transactions might have changed checkBalanceChanged(); - - int newNumTransactions = getNumTransactions(); - if(cachedNumTransactions != newNumTransactions) - { - cachedNumTransactions = newNumTransactions; - emit numTransactionsChanged(newNumTransactions); - } } void WalletModel::updateAddressBook(const QString &address, const QString &label, @@ -185,6 +177,12 @@ void WalletModel::updateAddressBook(const QString &address, const QString &label addressTableModel->updateEntry(address, label, isMine, purpose, status); } +void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly) +{ + fHaveWatchOnly = fHaveWatchonly; + emit notifyWatchonlyChanged(fHaveWatchonly); +} + bool WalletModel::validateAddress(const QString &address) { CBitcoinAddress addressParsed(address.toStdString()); @@ -499,6 +497,12 @@ static void ShowProgress(WalletModel *walletmodel, const std::string &title, int } } +static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly) +{ + QMetaObject::invokeMethod(walletmodel, "updateWatchOnlyFlag", Qt::QueuedConnection, + Q_ARG(bool, fHaveWatchonly)); +} + void WalletModel::subscribeToCoreSignals() { // Connect signals to wallet @@ -506,6 +510,7 @@ void WalletModel::subscribeToCoreSignals() wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); + wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, _1)); } void WalletModel::unsubscribeFromCoreSignals() @@ -515,6 +520,7 @@ void WalletModel::unsubscribeFromCoreSignals() wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); + wallet->NotifyWatchonlyChanged.disconnect(boost::bind(NotifyWatchonlyChanged, this, _1)); } // WalletModel::UnlockContext implementation diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 2bb91d85a9..b3a401e4cc 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -128,10 +128,10 @@ public: qint64 getBalance(const CCoinControl *coinControl = NULL) const; qint64 getUnconfirmedBalance() const; qint64 getImmatureBalance() const; + bool haveWatchOnly() const; qint64 getWatchBalance() const; qint64 getWatchUnconfirmedBalance() const; qint64 getWatchImmatureBalance() const; - int getNumTransactions() const; EncryptionStatus getEncryptionStatus() const; bool processingQueuedTransactions() { return fProcessingQueuedTransactions; } @@ -198,6 +198,7 @@ public: private: CWallet *wallet; bool fProcessingQueuedTransactions; + bool fHaveWatchOnly; // Wallet has an options model for wallet-specific options // (transaction fee, for example) @@ -214,7 +215,6 @@ private: qint64 cachedWatchOnlyBalance; qint64 cachedWatchUnconfBalance; qint64 cachedWatchImmatureBalance; - qint64 cachedNumTransactions; EncryptionStatus cachedEncryptionStatus; int cachedNumBlocks; @@ -229,9 +229,6 @@ signals: void balanceChanged(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance, qint64 watchOnlyBalance, qint64 watchUnconfBalance, qint64 watchImmatureBalance); - // Number of transactions in wallet changed - void numTransactionsChanged(int count); - // Encryption status of wallet changed void encryptionStatusChanged(int status); @@ -249,6 +246,9 @@ signals: // Show progress dialog e.g. for rescan void showProgress(const QString &title, int nProgress); + // Watch-only address added + void notifyWatchonlyChanged(bool fHaveWatchonly); + public slots: /* Wallet status might have changed */ void updateStatus(); @@ -256,6 +256,8 @@ public slots: void updateTransaction(const QString &hash, int status); /* New, updated or removed address book entry */ void updateAddressBook(const QString &address, const QString &label, bool isMine, const QString &purpose, int status); + /* Watchonly added */ + void updateWatchOnlyFlag(bool fHaveWatchonly); /* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */ void pollBalanceChanged(); /* Needed to update fProcessingQueuedTransactions through a QueuedConnection */ diff --git a/src/random.cpp b/src/random.cpp index 0d20d205ac..22c942acc0 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -8,12 +8,14 @@ #ifdef WIN32 #include "compat.h" // for Windows API #endif +#include "serialize.h" // for begin_ptr(vec) #include "util.h" // for LogPrint() +#include "utilstrencodings.h" // for GetTime() #ifndef WIN32 #include <sys/time.h> #endif - +#include <limits> #include <openssl/crypto.h> #include <openssl/err.h> #include <openssl/rand.h> diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 1e5198b85c..58cab14045 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -7,6 +7,7 @@ #include "main.h" #include "rpcserver.h" #include "sync.h" +#include "util.h" #include <stdint.h> @@ -531,3 +532,27 @@ Value getchaintips(const Array& params, bool fHelp) return res; } + +Value getmempoolinfo(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getmempoolinfo\n" + "\nReturns details on the active state of the TX memory pool.\n" + "\nResult:\n" + "{\n" + " \"size\": xxxxx (numeric) Current tx count\n" + " \"bytes\": xxxxx (numeric) Sum of all tx sizes\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getmempoolinfo", "") + + HelpExampleRpc("getmempoolinfo", "") + ); + + Object ret; + ret.push_back(Pair("size", (int64_t) mempool.size())); + ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize())); + + return ret; +} + diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index ff2361482b..e68ddee040 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -7,6 +7,8 @@ #include "init.h" #include "main.h" #include "sync.h" +#include "utiltime.h" +#include "util.h" #include "wallet.h" #include <fstream> diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index edab427cbf..e4a5bc4162 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -11,6 +11,7 @@ #include "miner.h" #include "pow.h" #include "core_io.h" +#include "util.h" #ifdef ENABLE_WALLET #include "db.h" #include "wallet.h" @@ -457,7 +458,7 @@ Value getblocktemplate(const Array& params, bool fHelp) CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Update nTime - UpdateTime(*pblock, pindexPrev); + UpdateTime(pblock, pindexPrev); pblock->nNonce = 0; Array transactions; diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 88e7c4ab07..2baa481c4e 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -338,6 +338,26 @@ Value getnettotals(const Array& params, bool fHelp) return obj; } +static Array GetNetworksInfo() +{ + Array networks; + for(int n=0; n<NET_MAX; ++n) + { + enum Network network = static_cast<enum Network>(n); + if(network == NET_UNROUTABLE) + continue; + proxyType proxy; + Object obj; + GetProxy(network, proxy); + obj.push_back(Pair("name", GetNetworkName(network))); + obj.push_back(Pair("limited", IsLimited(network))); + obj.push_back(Pair("reachable", IsReachable(network))); + obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.ToStringIPPort() : string())); + networks.push_back(obj); + } + return networks; +} + Value getnetworkinfo(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -351,7 +371,13 @@ Value getnetworkinfo(const Array& params, bool fHelp) " \"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" + " \"networks\": [ (array) information per network\n" + " \"name\": \"xxx\", (string) network (ipv4, ipv6 or onion)\n" + " \"limited\": xxx, (boolean) is the network limited using -onlynet?\n" + " \"reachable\": xxx, (boolean) is the network reachable?\n" + " \"proxy\": \"host:port\" (string) the proxy that is used for this network, or empty if none\n" + " },\n" + " ],\n" " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n" " \"localaddresses\": [, (array) list of local addresses\n" " \"address\": \"xxxx\", (string) network address\n" @@ -364,16 +390,13 @@ Value getnetworkinfo(const Array& params, bool fHelp) + HelpExampleRpc("getnetworkinfo", "") ); - proxyType proxy; - GetProxy(NET_IPV4, proxy); - Object obj; obj.push_back(Pair("version", (int)CLIENT_VERSION)); obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION)); obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices))); obj.push_back(Pair("timeoffset", GetTimeOffset())); obj.push_back(Pair("connections", (int)vNodes.size())); - obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string()))); + obj.push_back(Pair("networks", GetNetworksInfo())); obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); Array localAddresses; { diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp index 643208b3b6..808b9bbd2a 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpcprotocol.cpp @@ -6,6 +6,10 @@ #include "rpcprotocol.h" #include "util.h" +#include "tinyformat.h" +#include "utilstrencodings.h" +#include "utiltime.h" +#include "version.h" #include <stdint.h> diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 763615120a..7cd704193d 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -738,9 +738,7 @@ Value sendrawtransaction(const Array& params, bool fHelp) if (!fHaveMempool && !fHaveChain) { // push to local node and sync with wallets CValidationState state; - if (AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees)) - SyncWithWallets(tx, NULL); - else { + if (!AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees)) { if(state.IsInvalid()) throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); else diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 56064941f6..c9133bd3d2 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -23,6 +23,7 @@ #include <boost/iostreams/concepts.hpp> #include <boost/iostreams/stream.hpp> #include <boost/shared_ptr.hpp> +#include <boost/thread.hpp> #include "json/json_spirit_writer_template.h" using namespace boost; @@ -82,6 +83,11 @@ void RPCTypeCheck(const Object& o, } } +static inline int64_t roundint64(double d) +{ + return (int64_t)(d > 0 ? d + 0.5 : d - 0.5); +} + int64_t AmountFromValue(const Value& value) { double dAmount = value.get_real(); @@ -256,6 +262,7 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "getblockhash", &getblockhash, true, false, false }, { "blockchain", "getchaintips", &getchaintips, true, false, false }, { "blockchain", "getdifficulty", &getdifficulty, true, false, false }, + { "blockchain", "getmempoolinfo", &getmempoolinfo, true, true, false }, { "blockchain", "getrawmempool", &getrawmempool, true, false, false }, { "blockchain", "gettxout", &gettxout, true, false, false }, { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false, false }, @@ -848,11 +855,10 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn, if (!HTTPAuthorized(mapHeaders)) { LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string()); - /* Deter brute-forcing short passwords. + /* Deter brute-forcing If this results in a DoS the user really shouldn't have their RPC port exposed. */ - if (mapArgs["-rpcpassword"].size() < 20) - MilliSleep(250); + MilliSleep(250); conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush; return false; diff --git a/src/rpcserver.h b/src/rpcserver.h index 2248e8aeb2..b850d15d4e 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -200,6 +200,7 @@ extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool f extern json_spirit::Value getbestblockhash(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getdifficulty(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value settxfee(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getmempoolinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getrawmempool(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp); diff --git a/src/script.cpp b/src/script.cpp index 942e8810db..28c50a1358 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -18,8 +18,9 @@ #include "util.h" #include <boost/foreach.hpp> -#include <boost/tuple/tuple.hpp> +#include <boost/thread.hpp> #include <boost/tuple/tuple_comparison.hpp> +#include <boost/tuple/tuple.hpp> using namespace std; using namespace boost; @@ -1874,9 +1875,11 @@ bool CScript::IsPushOnly() const const_iterator pc = begin(); while (pc < end()) { + // Note how a script with an invalid PUSHDATA returns False. opcodetype opcode; if (!GetOp(pc, opcode)) return false; + // Note that IsPushOnly() *does* consider OP_RESERVED to be a // push-type opcode, however execution of OP_RESERVED fails, so // it's not relevant to P2SH as the scriptSig would fail prior to diff --git a/src/script.h b/src/script.h index 7cb863d1c9..462e3f2302 100644 --- a/src/script.h +++ b/src/script.h @@ -7,7 +7,8 @@ #define H_BITCOIN_SCRIPT #include "key.h" -#include "util.h" +#include "utilstrencodings.h" +#include "tinyformat.h" #include <stdexcept> #include <stdint.h> @@ -730,6 +731,12 @@ public: { return CScriptID(Hash160(*this)); } + + void clear() + { + // The default std::vector::clear() does not release memory. + std::vector<unsigned char>().swap(*this); + } }; /** Compact serializer for scripts. diff --git a/src/serialize.h b/src/serialize.h index f876efd9b5..17cb724bee 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -68,7 +68,7 @@ inline const T* end_ptr(const std::vector<T,TAl>& v) ///////////////////////////////////////////////////////////////// // // Templates for serializing to anything that looks like a stream, -// i.e. anything that supports .read(char*, int) and .write(char*, int) +// i.e. anything that supports .read(char*, size_t) and .write(char*, size_t) // enum @@ -334,8 +334,9 @@ I ReadVarInt(Stream& is) } } -#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) -#define VARINT(obj) REF(WrapVarInt(REF(obj))) +#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) +#define VARINT(obj) REF(WrapVarInt(REF(obj))) +#define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj))) /** Wrapper for serializing arrays and POD. */ @@ -398,6 +399,40 @@ public: } }; +template<size_t Limit> +class LimitedString +{ +protected: + std::string& string; +public: + LimitedString(std::string& string) : string(string) {} + + template<typename Stream> + void Unserialize(Stream& s, int, int=0) + { + size_t size = ReadCompactSize(s); + if (size > Limit) { + throw std::ios_base::failure("String length limit exceeded"); + } + string.resize(size); + if (size != 0) + s.read((char*)&string[0], size); + } + + template<typename Stream> + void Serialize(Stream& s, int, int=0) const + { + WriteCompactSize(s, string.size()); + if (!string.empty()) + s.write((char*)&string[0], string.size()); + } + + unsigned int GetSerializeSize(int, int=0) const + { + return GetSizeOfCompactSize(string.size()) + string.size(); + } +}; + template<typename I> CVarInt<I> WrapVarInt(I& n) { return CVarInt<I>(n); } @@ -841,7 +876,7 @@ public: CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {} - CSizeComputer& write(const char *psz, int nSize) + CSizeComputer& write(const char *psz, size_t nSize) { this->nSize += nSize; return *this; @@ -870,8 +905,6 @@ protected: typedef CSerializeData vector_type; vector_type vch; unsigned int nReadPos; - short state; - short exceptmask; public: int nType; int nVersion; @@ -923,8 +956,6 @@ public: nReadPos = 0; nType = nTypeIn; nVersion = nVersionIn; - state = 0; - exceptmask = std::ios::badbit | std::ios::failbit; } CDataStream& operator+=(const CDataStream& b) @@ -1047,19 +1078,7 @@ public: // // Stream subset // - void setstate(short bits, const char* psz) - { - state |= bits; - if (state & exceptmask) - throw std::ios_base::failure(psz); - } - bool eof() const { return size() == 0; } - bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } - bool good() const { return !eof() && (state == 0); } - void clear(short n) { state = n; } // name conflict with vector clear() - short exceptions() { return exceptmask; } - short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; } CDataStream* rdbuf() { return this; } int in_avail() { return size(); } @@ -1070,18 +1089,15 @@ public: void ReadVersion() { *this >> nVersion; } void WriteVersion() { *this << nVersion; } - CDataStream& read(char* pch, int nSize) + CDataStream& read(char* pch, size_t nSize) { // Read from the beginning of the buffer - assert(nSize >= 0); unsigned int nReadPosNext = nReadPos + nSize; if (nReadPosNext >= vch.size()) { if (nReadPosNext > vch.size()) { - setstate(std::ios::failbit, "CDataStream::read() : end of data"); - memset(pch, 0, nSize); - nSize = vch.size() - nReadPos; + throw std::ios_base::failure("CDataStream::read() : end of data"); } memcpy(pch, &vch[nReadPos], nSize); nReadPos = 0; @@ -1101,7 +1117,7 @@ public: if (nReadPosNext >= vch.size()) { if (nReadPosNext > vch.size()) - setstate(std::ios::failbit, "CDataStream::ignore() : end of data"); + throw std::ios_base::failure("CDataStream::ignore() : end of data"); nReadPos = 0; vch.clear(); return (*this); @@ -1110,10 +1126,9 @@ public: return (*this); } - CDataStream& write(const char* pch, int nSize) + CDataStream& write(const char* pch, size_t nSize) { // Write to the end of the buffer - assert(nSize >= 0); vch.insert(vch.end(), pch, pch + nSize); return (*this); } @@ -1174,8 +1189,6 @@ class CAutoFile { protected: FILE* file; - short state; - short exceptmask; public: int nType; int nVersion; @@ -1185,8 +1198,6 @@ public: file = filenew; nType = nTypeIn; nVersion = nVersionIn; - state = 0; - exceptmask = std::ios::badbit | std::ios::failbit; } ~CAutoFile() @@ -1213,19 +1224,6 @@ public: // // Stream subset // - void setstate(short bits, const char* psz) - { - state |= bits; - if (state & exceptmask) - throw std::ios_base::failure(psz); - } - - bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } - bool good() const { return state == 0; } - void clear(short n = 0) { state = n; } - short exceptions() { return exceptmask; } - short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; } - void SetType(int n) { nType = n; } int GetType() { return nType; } void SetVersion(int n) { nVersion = n; } @@ -1238,7 +1236,7 @@ public: if (!file) throw std::ios_base::failure("CAutoFile::read : file handle is NULL"); if (fread(pch, 1, nSize, file) != nSize) - setstate(std::ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); + throw std::ios_base::failure(feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); return (*this); } @@ -1247,7 +1245,7 @@ public: if (!file) throw std::ios_base::failure("CAutoFile::write : file handle is NULL"); if (fwrite(pch, 1, nSize, file) != nSize) - setstate(std::ios::failbit, "CAutoFile::write : write failed"); + throw std::ios_base::failure("CAutoFile::write : write failed"); return (*this); } @@ -1292,16 +1290,7 @@ private: uint64_t nRewind; // how many bytes we guarantee to rewind std::vector<char> vchBuf; // the buffer - short state; - short exceptmask; - protected: - void setstate(short bits, const char *psz) { - state |= bits; - if (state & exceptmask) - throw std::ios_base::failure(psz); - } - // read data from the source to fill the buffer bool Fill() { unsigned int pos = nSrcPos % vchBuf.size(); @@ -1313,8 +1302,7 @@ protected: return false; size_t read = fread((void*)&vchBuf[pos], 1, readNow, src); if (read == 0) { - setstate(std::ios_base::failbit, feof(src) ? "CBufferedFile::Fill : end of file" : "CBufferedFile::Fill : fread failed"); - return false; + throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill : end of file" : "CBufferedFile::Fill : fread failed"); } else { nSrcPos += read; return true; @@ -1327,12 +1315,7 @@ public: CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) : src(fileIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0), - state(0), exceptmask(std::ios_base::badbit | std::ios_base::failbit), nType(nTypeIn), nVersion(nVersionIn) { - } - - // check whether no error occurred - bool good() const { - return state == 0; + nType(nTypeIn), nVersion(nVersionIn) { } // check whether we're at the end of the source file @@ -1391,7 +1374,6 @@ public: nLongPos = ftell(src); nSrcPos = nLongPos; nReadPos = nLongPos; - state = 0; return true; } diff --git a/src/sync.cpp b/src/sync.cpp index e624a9ee84..066c1ca744 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -5,8 +5,11 @@ #include "sync.h" #include "util.h" +#include "utilstrencodings.h" #include <boost/foreach.hpp> +#include <boost/thread.hpp> +#include <stdio.h> #ifdef DEBUG_LOCKCONTENTION void PrintLockContention(const char* pszName, const char* pszFile, int nLine) diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 5e17555e7a..8fa38c3605 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -14,6 +14,7 @@ #include "pow.h" #include "script.h" #include "serialize.h" +#include "util.h" #include <stdint.h> @@ -106,11 +107,7 @@ static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2, return CheckNBits(nbits2, time2, nbits1, time1); int64_t deltaTime = time2-time1; - uint256 required; - required.SetCompact(ComputeMinWork(nbits1, deltaTime)); - uint256 have; - have.SetCompact(nbits2); - return (have <= required); + return CheckMinWork(nbits2, nbits1, deltaTime); } BOOST_AUTO_TEST_CASE(DoS_checknbits) diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index b16f3f7f57..4af87cf8ef 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -11,6 +11,7 @@ #include "serialize.h" #include "util.h" +#include "utilstrencodings.h" #include "version.h" #include <fstream> @@ -83,7 +84,7 @@ struct ReadAlerts std::vector<unsigned char> vch(alert_tests::alertTests, alert_tests::alertTests + sizeof(alert_tests::alertTests)); CDataStream stream(vch, SER_DISK, CLIENT_VERSION); try { - while (stream.good()) + while (!stream.eof()) { CAlert alert; stream >> alert; diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index 2752a0b215..69888da3df 100644 --- a/src/test/allocator_tests.cpp +++ b/src/test/allocator_tests.cpp @@ -4,6 +4,8 @@ #include "util.h" +#include "allocators.h" + #include <boost/test/unit_test.hpp> BOOST_AUTO_TEST_SUITE(allocator_tests) diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index 87473585e3..68617abbdd 100644 --- a/src/test/base32_tests.cpp +++ b/src/test/base32_tests.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "util.h" +#include "utilstrencodings.h" #include <boost/test/unit_test.hpp> diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp index d4a23d9aa0..f2bf3326ad 100644 --- a/src/test/base64_tests.cpp +++ b/src/test/base64_tests.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "util.h" +#include "utilstrencodings.h" #include <boost/test/unit_test.hpp> diff --git a/src/test/bctest.py b/src/test/bctest.py new file mode 100644 index 0000000000..1839f4fef4 --- /dev/null +++ b/src/test/bctest.py @@ -0,0 +1,53 @@ +# Copyright 2014 BitPay, Inc. +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import subprocess +import os +import json +import sys + +def bctest(testDir, testObj): + execargs = testObj['exec'] + + stdinCfg = None + inputData = None + if "input" in testObj: + filename = testDir + "/" + testObj['input'] + inputData = open(filename).read() + stdinCfg = subprocess.PIPE + + outputFn = None + outputData = None + if "output_cmp" in testObj: + outputFn = testObj['output_cmp'] + outputData = open(testDir + "/" + outputFn).read() + + proc = subprocess.Popen(execargs, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + try: + outs = proc.communicate(input=inputData) + except OSError: + print("OSError, Failed to execute " + execargs[0]) + sys.exit(1) + + if outputData and (outs[0] != outputData): + print("Output data mismatch for " + outputFn) + sys.exit(1) + + wantRC = 0 + if "return_code" in testObj: + wantRC = testObj['return_code'] + if proc.returncode != wantRC: + print("Return code mismatch for " + outputFn) + sys.exit(1) + +def bctester(testDir, input_basename): + input_filename = testDir + "/" + input_basename + raw_data = open(input_filename).read() + input_data = json.loads(raw_data) + + for testObj in input_data: + bctest(testDir, testObj) + + sys.exit(0) + diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py new file mode 100755 index 0000000000..40690c2fed --- /dev/null +++ b/src/test/bitcoin-util-test.py @@ -0,0 +1,12 @@ +#!/usr/bin/python +# Copyright 2014 BitPay, Inc. +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import os +import bctest + +if __name__ == '__main__': + bctest.bctester(os.environ["srcdir"] + "/test/data", + "bitcoin-util-test.json") + diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index 10352240f4..fdea12846a 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -9,6 +9,7 @@ #include "main.h" +#include "utiltime.h" #include <cstdio> diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index a17278b803..a3eec270ee 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -6,7 +6,7 @@ #include "crypto/sha1.h" #include "crypto/sha2.h" #include "random.h" -#include "util.h" +#include "utilstrencodings.h" #include <vector> diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json new file mode 100644 index 0000000000..7db87d7c11 --- /dev/null +++ b/src/test/data/bitcoin-util-test.json @@ -0,0 +1,38 @@ +[ + { "exec": ["./bitcoin-tx", "-create"], + "output_cmp": "blanktx.hex" + }, + { "exec": ["./bitcoin-tx", "-"], + "input": "blanktx.hex", + "output_cmp": "blanktx.hex" + }, + { "exec": ["./bitcoin-tx", "-", "delin=1"], + "input": "tx394b54bb.hex", + "output_cmp": "tt-delin1-out.hex" + }, + { "exec": ["./bitcoin-tx", "-", "delin=31"], + "input": "tx394b54bb.hex", + "return_code": 1 + }, + { "exec": ["./bitcoin-tx", "-", "delout=1"], + "input": "tx394b54bb.hex", + "output_cmp": "tt-delout1-out.hex" + }, + { "exec": ["./bitcoin-tx", "-", "delout=2"], + "input": "tx394b54bb.hex", + "return_code": 1 + }, + { "exec": ["./bitcoin-tx", "-", "locktime=317000"], + "input": "tx394b54bb.hex", + "output_cmp": "tt-locktime317000-out.hex" + }, + { "exec": + ["./bitcoin-tx", "-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18", + "in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1", + "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o", + "outaddr=4:1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46"], + "output_cmp": "txcreate1.hex" + } +] diff --git a/src/test/data/blanktx.hex b/src/test/data/blanktx.hex new file mode 100644 index 0000000000..36b6f00fb6 --- /dev/null +++ b/src/test/data/blanktx.hex @@ -0,0 +1 @@ +01000000000000000000 diff --git a/src/test/data/tt-delin1-out.hex b/src/test/data/tt-delin1-out.hex new file mode 100644 index 0000000000..42ad840f43 --- /dev/null +++ b/src/test/data/tt-delin1-out.hex @@ -0,0 +1 @@ +0100000014fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000 diff --git a/src/test/data/tt-delout1-out.hex b/src/test/data/tt-delout1-out.hex new file mode 100644 index 0000000000..cc60c3fac6 --- /dev/null +++ b/src/test/data/tt-delout1-out.hex @@ -0,0 +1 @@ +0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0160f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac00000000 diff --git a/src/test/data/tt-locktime317000-out.hex b/src/test/data/tt-locktime317000-out.hex new file mode 100644 index 0000000000..287f420a40 --- /dev/null +++ b/src/test/data/tt-locktime317000-out.hex @@ -0,0 +1 @@ +0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac48d60400 diff --git a/src/test/data/tx394b54bb.hex b/src/test/data/tx394b54bb.hex new file mode 100644 index 0000000000..33f26cb4d6 --- /dev/null +++ b/src/test/data/tx394b54bb.hex @@ -0,0 +1 @@ +0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000 diff --git a/src/test/data/txcreate1.hex b/src/test/data/txcreate1.hex new file mode 100644 index 0000000000..e2981a51c9 --- /dev/null +++ b/src/test/data/txcreate1.hex @@ -0,0 +1 @@ +01000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fffffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d717000000001976a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac00000000 diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index 4568c8769b..b8e290f071 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -3,7 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "hash.h" -#include "util.h" +#include "utilstrencodings.h" #include <vector> diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 2a0466e928..02c6d095f2 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -164,9 +164,9 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) // Tests Solver() that returns lists of keys that are // required to satisfy a ScriptPubKey // - // Also tests IsMine() and ExtractAddress() + // Also tests IsMine() and ExtractDestination() // - // Note: ExtractAddress for the multisignature transactions + // Note: ExtractDestination for the multisignature transactions // always returns false for this release, even if you have // one key that would satisfy an (a|b) or 2-of-3 keys needed // to spend an escrow transaction. diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 107c0f06e7..d5475a92bf 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -110,14 +110,14 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign) BOOST_AUTO_TEST_CASE(rpc_format_monetary_values) { - BOOST_CHECK(write_string(ValueFromAmount(0LL), false) == "0.00000000"); - BOOST_CHECK(write_string(ValueFromAmount(1LL), false) == "0.00000001"); - BOOST_CHECK(write_string(ValueFromAmount(17622195LL), false) == "0.17622195"); - BOOST_CHECK(write_string(ValueFromAmount(50000000LL), false) == "0.50000000"); - BOOST_CHECK(write_string(ValueFromAmount(89898989LL), false) == "0.89898989"); - BOOST_CHECK(write_string(ValueFromAmount(100000000LL), false) == "1.00000000"); - BOOST_CHECK(write_string(ValueFromAmount(2099999999999990LL), false) == "20999999.99999990"); - BOOST_CHECK(write_string(ValueFromAmount(2099999999999999LL), false) == "20999999.99999999"); + BOOST_CHECK_EQUAL(write_string(ValueFromAmount(0LL), false), "0.00000000"); + BOOST_CHECK_EQUAL(write_string(ValueFromAmount(1LL), false), "0.00000001"); + BOOST_CHECK_EQUAL(write_string(ValueFromAmount(17622195LL), false), "0.17622195"); + BOOST_CHECK_EQUAL(write_string(ValueFromAmount(50000000LL), false), "0.50000000"); + BOOST_CHECK_EQUAL(write_string(ValueFromAmount(89898989LL), false), "0.89898989"); + BOOST_CHECK_EQUAL(write_string(ValueFromAmount(100000000LL), false), "1.00000000"); + BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999990LL), false), "20999999.99999990"); + BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999999LL), false), "20999999.99999999"); } static Value ValueFromString(const std::string &str) @@ -129,14 +129,14 @@ static Value ValueFromString(const std::string &str) BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values) { - BOOST_CHECK(AmountFromValue(ValueFromString("0.00000001")) == 1LL); - BOOST_CHECK(AmountFromValue(ValueFromString("0.17622195")) == 17622195LL); - BOOST_CHECK(AmountFromValue(ValueFromString("0.5")) == 50000000LL); - BOOST_CHECK(AmountFromValue(ValueFromString("0.50000000")) == 50000000LL); - BOOST_CHECK(AmountFromValue(ValueFromString("0.89898989")) == 89898989LL); - BOOST_CHECK(AmountFromValue(ValueFromString("1.00000000")) == 100000000LL); - BOOST_CHECK(AmountFromValue(ValueFromString("20999999.9999999")) == 2099999999999990LL); - BOOST_CHECK(AmountFromValue(ValueFromString("20999999.99999999")) == 2099999999999999LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001")), 1LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.17622195")), 17622195LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.5")), 50000000LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.50000000")), 50000000LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.89898989")), 89898989LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1.00000000")), 100000000LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.9999999")), 2099999999999990LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.99999999")), 2099999999999999LL); } BOOST_AUTO_TEST_CASE(rpc_boostasiotocnetaddr) diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index bc9f31c077..77c44501ab 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -394,4 +394,15 @@ BOOST_AUTO_TEST_CASE(script_standard_push) } } +BOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts) +{ + // IsPushOnly returns false when given a script containing only pushes that + // are invalid due to truncation. IsPushOnly() is consensus critical + // because P2SH evaluation uses it, although this specific behavior should + // not be consensus critical as the P2SH evaluation would fail first due to + // the invalid push. Still, it doesn't hurt to test it explicitly. + static const unsigned char direct[] = { 1 }; + BOOST_CHECK(!CScript(direct, direct+sizeof(direct)).IsPushOnly()); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 443b5853b2..68fad8d038 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -16,6 +16,7 @@ #include <boost/filesystem.hpp> #include <boost/test/unit_test.hpp> +#include <boost/thread.hpp> CClientUIInterface uiInterface; CWallet* pwalletMain; diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp new file mode 100644 index 0000000000..aa4fa0d500 --- /dev/null +++ b/src/test/timedata_tests.cpp @@ -0,0 +1,38 @@ +// Copyright (c) 2011-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 "timedata.h" + +#include <boost/test/unit_test.hpp> + +using namespace std; + +BOOST_AUTO_TEST_SUITE(timedata_tests) + +BOOST_AUTO_TEST_CASE(util_MedianFilter) +{ + CMedianFilter<int> filter(5, 15); + + BOOST_CHECK_EQUAL(filter.median(), 15); + + filter.input(20); // [15 20] + BOOST_CHECK_EQUAL(filter.median(), 17); + + filter.input(30); // [15 20 30] + BOOST_CHECK_EQUAL(filter.median(), 20); + + filter.input(3); // [3 15 20 30] + BOOST_CHECK_EQUAL(filter.median(), 17); + + filter.input(7); // [3 7 15 20 30] + BOOST_CHECK_EQUAL(filter.median(), 15); + + filter.input(18); // [3 7 18 20 30] + BOOST_CHECK_EQUAL(filter.median(), 18); + + filter.input(0); // [0 3 7 18 30] + BOOST_CHECK_EQUAL(filter.median(), 7); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp new file mode 100644 index 0000000000..23bc5f6b12 --- /dev/null +++ b/src/test/univalue_tests.cpp @@ -0,0 +1,275 @@ +// Copyright 2014 BitPay, Inc. +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <stdint.h> +#include <vector> +#include <string> +#include <map> +#include "univalue/univalue.h" + +#include <boost/test/unit_test.hpp> + +using namespace std; + +BOOST_AUTO_TEST_SUITE(univalue_tests) + +BOOST_AUTO_TEST_CASE(univalue_constructor) +{ + UniValue v1; + BOOST_CHECK(v1.isNull()); + + UniValue v2(UniValue::VSTR); + BOOST_CHECK(v2.isStr()); + + UniValue v3(UniValue::VSTR, "foo"); + BOOST_CHECK(v3.isStr()); + BOOST_CHECK_EQUAL(v3.getValStr(), "foo"); + + UniValue numTest; + BOOST_CHECK(numTest.setNumStr("82")); + BOOST_CHECK(numTest.isNum()); + BOOST_CHECK_EQUAL(numTest.getValStr(), "82"); + + uint64_t vu64 = 82; + UniValue v4(vu64); + BOOST_CHECK(v4.isNum()); + BOOST_CHECK_EQUAL(v4.getValStr(), "82"); + + int64_t vi64 = -82; + UniValue v5(vi64); + BOOST_CHECK(v5.isNum()); + BOOST_CHECK_EQUAL(v5.getValStr(), "-82"); + + int vi = -688; + UniValue v6(vi); + BOOST_CHECK(v6.isNum()); + BOOST_CHECK_EQUAL(v6.getValStr(), "-688"); + + double vd = -7.21; + UniValue v7(vd); + BOOST_CHECK(v7.isNum()); + BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21"); + + string vs("yawn"); + UniValue v8(vs); + BOOST_CHECK(v8.isStr()); + BOOST_CHECK_EQUAL(v8.getValStr(), "yawn"); + + const char *vcs = "zappa"; + UniValue v9(vcs); + BOOST_CHECK(v9.isStr()); + BOOST_CHECK_EQUAL(v9.getValStr(), "zappa"); +} + +BOOST_AUTO_TEST_CASE(univalue_set) +{ + UniValue v(UniValue::VSTR, "foo"); + v.clear(); + BOOST_CHECK(v.isNull()); + BOOST_CHECK_EQUAL(v.getValStr(), ""); + + BOOST_CHECK(v.setObject()); + BOOST_CHECK(v.isObject()); + BOOST_CHECK_EQUAL(v.count(), 0); + BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ); + BOOST_CHECK(v.empty()); + + BOOST_CHECK(v.setArray()); + BOOST_CHECK(v.isArray()); + BOOST_CHECK_EQUAL(v.count(), 0); + + BOOST_CHECK(v.setStr("zum")); + BOOST_CHECK(v.isStr()); + BOOST_CHECK_EQUAL(v.getValStr(), "zum"); + + BOOST_CHECK(v.setFloat(-1.01)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-1.01"); + + BOOST_CHECK(v.setInt((int)1023)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "1023"); + + BOOST_CHECK(v.setInt((int64_t)-1023LL)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-1023"); + + BOOST_CHECK(v.setInt((uint64_t)1023ULL)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "1023"); + + BOOST_CHECK(v.setNumStr("-688")); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-688"); + + BOOST_CHECK(v.setBool(false)); + BOOST_CHECK_EQUAL(v.isBool(), true); + BOOST_CHECK_EQUAL(v.isTrue(), false); + BOOST_CHECK_EQUAL(v.isFalse(), true); + BOOST_CHECK_EQUAL(v.getBool(), false); + + BOOST_CHECK(v.setBool(true)); + BOOST_CHECK_EQUAL(v.isBool(), true); + BOOST_CHECK_EQUAL(v.isTrue(), true); + BOOST_CHECK_EQUAL(v.isFalse(), false); + BOOST_CHECK_EQUAL(v.getBool(), true); + + BOOST_CHECK(!v.setNumStr("zombocom")); + + BOOST_CHECK(v.setNull()); + BOOST_CHECK(v.isNull()); +} + +BOOST_AUTO_TEST_CASE(univalue_array) +{ + UniValue arr(UniValue::VARR); + + UniValue v((int64_t)1023LL); + BOOST_CHECK(arr.push_back(v)); + + string vStr("zippy"); + BOOST_CHECK(arr.push_back(vStr)); + + const char *s = "pippy"; + BOOST_CHECK(arr.push_back(s)); + + vector<UniValue> vec; + v.setStr("boing"); + vec.push_back(v); + + v.setStr("going"); + vec.push_back(v); + + BOOST_CHECK(arr.push_backV(vec)); + + BOOST_CHECK_EQUAL(arr.empty(), false); + BOOST_CHECK_EQUAL(arr.count(), 5); + + BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023"); + BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy"); + BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy"); + BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing"); + BOOST_CHECK_EQUAL(arr[4].getValStr(), "going"); + + BOOST_CHECK_EQUAL(arr[999].getValStr(), ""); + + arr.clear(); + BOOST_CHECK(arr.empty()); + BOOST_CHECK_EQUAL(arr.count(), 0); +} + +BOOST_AUTO_TEST_CASE(univalue_object) +{ + UniValue obj(UniValue::VOBJ); + string strKey, strVal; + UniValue v; + + strKey = "age"; + v.setInt(100); + BOOST_CHECK(obj.pushKV(strKey, v)); + + strKey = "first"; + strVal = "John"; + BOOST_CHECK(obj.pushKV(strKey, strVal)); + + strKey = "last"; + const char *cVal = "Smith"; + BOOST_CHECK(obj.pushKV(strKey, cVal)); + + strKey = "distance"; + BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25)); + + strKey = "time"; + BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600)); + + strKey = "calories"; + BOOST_CHECK(obj.pushKV(strKey, (int) 12)); + + strKey = "temperature"; + BOOST_CHECK(obj.pushKV(strKey, (double) 90.012)); + + UniValue obj2(UniValue::VOBJ); + BOOST_CHECK(obj2.pushKV("cat1", 9000)); + BOOST_CHECK(obj2.pushKV("cat2", 12345)); + + BOOST_CHECK(obj.pushKVs(obj2)); + + BOOST_CHECK_EQUAL(obj.empty(), false); + BOOST_CHECK_EQUAL(obj.count(), 9); + + BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100"); + BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John"); + BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith"); + BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25"); + BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600"); + BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12"); + BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012"); + BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000"); + BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345"); + + BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), ""); + + BOOST_CHECK(obj.exists("age")); + BOOST_CHECK(obj.exists("first")); + BOOST_CHECK(obj.exists("last")); + BOOST_CHECK(obj.exists("distance")); + BOOST_CHECK(obj.exists("time")); + BOOST_CHECK(obj.exists("calories")); + BOOST_CHECK(obj.exists("temperature")); + BOOST_CHECK(obj.exists("cat1")); + BOOST_CHECK(obj.exists("cat2")); + + BOOST_CHECK(!obj.exists("nyuknyuknyuk")); + + map<string, UniValue::VType> objTypes; + objTypes["age"] = UniValue::VNUM; + objTypes["first"] = UniValue::VSTR; + objTypes["last"] = UniValue::VSTR; + objTypes["distance"] = UniValue::VNUM; + objTypes["time"] = UniValue::VNUM; + objTypes["calories"] = UniValue::VNUM; + objTypes["temperature"] = UniValue::VNUM; + objTypes["cat1"] = UniValue::VNUM; + objTypes["cat2"] = UniValue::VNUM; + BOOST_CHECK(obj.checkObject(objTypes)); + + objTypes["cat2"] = UniValue::VSTR; + BOOST_CHECK(!obj.checkObject(objTypes)); + + obj.clear(); + BOOST_CHECK(obj.empty()); + BOOST_CHECK_EQUAL(obj.count(), 0); +} + +static const char *json1 = +"[1.1,{\"key1\":\"str\",\"key2\":800,\"key3\":{\"name\":\"martian\"}}]"; + +BOOST_AUTO_TEST_CASE(univalue_readwrite) +{ + UniValue v; + BOOST_CHECK(v.read(json1)); + + string strJson1(json1); + BOOST_CHECK(v.read(strJson1)); + + BOOST_CHECK(v.isArray()); + BOOST_CHECK_EQUAL(v.count(), 2); + + BOOST_CHECK_EQUAL(v[0].getValStr(), "1.1"); + + UniValue obj = v[1]; + BOOST_CHECK(obj.isObject()); + BOOST_CHECK_EQUAL(obj.count(), 3); + + BOOST_CHECK(obj["key1"].isStr()); + BOOST_CHECK_EQUAL(obj["key1"].getValStr(), "str"); + BOOST_CHECK(obj["key2"].isNum()); + BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800"); + BOOST_CHECK(obj["key3"].isObject()); + + BOOST_CHECK_EQUAL(strJson1, v.write()); +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 068b9f29c8..e077c9de3b 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -4,8 +4,11 @@ #include "util.h" +#include "core.h" #include "random.h" #include "sync.h" +#include "utilstrencodings.h" +#include "utilmoneystr.h" #include <stdint.h> #include <vector> @@ -36,31 +39,6 @@ BOOST_AUTO_TEST_CASE(util_criticalsection) } while(0); } -BOOST_AUTO_TEST_CASE(util_MedianFilter) -{ - CMedianFilter<int> filter(5, 15); - - BOOST_CHECK_EQUAL(filter.median(), 15); - - filter.input(20); // [15 20] - BOOST_CHECK_EQUAL(filter.median(), 17); - - filter.input(30); // [15 20 30] - BOOST_CHECK_EQUAL(filter.median(), 20); - - filter.input(3); // [3 15 20 30] - BOOST_CHECK_EQUAL(filter.median(), 17); - - filter.input(7); // [3 7 15 20 30] - BOOST_CHECK_EQUAL(filter.median(), 15); - - filter.input(18); // [3 7 18 20 30] - BOOST_CHECK_EQUAL(filter.median(), 18); - - filter.input(0); // [0 3 7 18 30] - BOOST_CHECK_EQUAL(filter.median(), 7); -} - static const unsigned char ParseHex_expected[65] = { 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, diff --git a/src/timedata.cpp b/src/timedata.cpp index 4576786b96..40cdb33f7a 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -8,6 +8,7 @@ #include "sync.h" #include "ui_interface.h" #include "util.h" +#include "utilstrencodings.h" #include <boost/foreach.hpp> @@ -35,6 +36,11 @@ int64_t GetAdjustedTime() return GetTime() + GetTimeOffset(); } +static int64_t abs64(int64_t n) +{ + return (n >= 0 ? n : -n); +} + void AddTimeData(const CNetAddr& ip, int64_t nTime) { int64_t nOffsetSample = nTime - GetTime(); diff --git a/src/timedata.h b/src/timedata.h index 0e7bdc2c1f..d0c84b3183 100644 --- a/src/timedata.h +++ b/src/timedata.h @@ -6,9 +6,68 @@ #define BITCOIN_TIMEDATA_H #include <stdint.h> +#include <vector> +#include <algorithm> +#include <assert.h> class CNetAddr; +/** Median filter over a stream of values. + * Returns the median of the last N numbers + */ +template <typename T> class CMedianFilter +{ +private: + std::vector<T> vValues; + std::vector<T> vSorted; + unsigned int nSize; +public: + CMedianFilter(unsigned int size, T initial_value): + nSize(size) + { + vValues.reserve(size); + vValues.push_back(initial_value); + vSorted = vValues; + } + + void input(T value) + { + if(vValues.size() == nSize) + { + vValues.erase(vValues.begin()); + } + vValues.push_back(value); + + vSorted.resize(vValues.size()); + std::copy(vValues.begin(), vValues.end(), vSorted.begin()); + std::sort(vSorted.begin(), vSorted.end()); + } + + T median() const + { + int size = vSorted.size(); + assert(size>0); + if(size & 1) // Odd number of elements + { + return vSorted[size/2]; + } + else // Even number of elements + { + return (vSorted[size/2-1] + vSorted[size/2]) / 2; + } + } + + int size() const + { + return vValues.size(); + } + + std::vector<T> sorted () const + { + return vSorted; + } +}; + /* Functions to keep track of adjusted P2P time */ int64_t GetTimeOffset(); int64_t GetAdjustedTime(); diff --git a/src/tinyformat.h b/src/tinyformat.h index b6113029f5..73d49a1fe4 100644 --- a/src/tinyformat.h +++ b/src/tinyformat.h @@ -121,6 +121,7 @@ namespace tfm = tinyformat; #include <cassert> #include <iostream> #include <sstream> +#include <stdexcept> #ifndef TINYFORMAT_ERROR # define TINYFORMAT_ERROR(reason) assert(0 && reason) @@ -1007,4 +1008,6 @@ TINYFORMAT_WRAP_FORMAT_N(16, returnType, funcName, funcDeclSuffix, bodyPrefix, s } // namespace tinyformat +#define strprintf tfm::format + #endif // TINYFORMAT_H_INCLUDED diff --git a/src/txdb.cpp b/src/txdb.cpp index 52cd96283e..d4c6007558 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -9,6 +9,7 @@ #include "pow.h" #include "uint256.h" +#include <boost/thread.hpp> #include <stdint.h> using namespace std; @@ -27,7 +28,7 @@ void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) { CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) { } -bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) { +bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const { return db.Read(make_pair('c', txid), coins); } @@ -37,11 +38,11 @@ bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) { return db.WriteBatch(batch); } -bool CCoinsViewDB::HaveCoins(const uint256 &txid) { +bool CCoinsViewDB::HaveCoins(const uint256 &txid) const { return db.Exists(make_pair('c', txid)); } -uint256 CCoinsViewDB::GetBestBlock() { +uint256 CCoinsViewDB::GetBestBlock() const { uint256 hashBestChain; if (!db.Read('B', hashBestChain)) return uint256(0); @@ -54,12 +55,15 @@ bool CCoinsViewDB::SetBestBlock(const uint256 &hashBlock) { return db.WriteBatch(batch); } -bool CCoinsViewDB::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) { +bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { LogPrint("coindb", "Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size()); CLevelDBBatch batch; - for (CCoinsMap::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++) + for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { BatchWriteCoins(batch, it->first, it->second); + CCoinsMap::iterator itOld = it++; + mapCoins.erase(itOld); + } if (hashBlock != uint256(0)) BatchWriteHashBestChain(batch, hashBlock); @@ -102,8 +106,11 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) { return Read('l', nFile); } -bool CCoinsViewDB::GetStats(CCoinsStats &stats) { - leveldb::Iterator *pcursor = db.NewIterator(); +bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { + /* It seems that there are no "const iterators" for LevelDB. Since we + only need read operations on it, use a const-cast to get around + that restriction. */ + leveldb::Iterator *pcursor = const_cast<CLevelDBWrapper*>(&db)->NewIterator(); pcursor->SeekToFirst(); CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); @@ -146,7 +153,6 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) { return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } } - delete pcursor; stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight; stats.hashSerialized = ss.GetHash(); stats.nTotalAmount = nTotalAmount; @@ -178,7 +184,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { bool CBlockTreeDB::LoadBlockIndexGuts() { - leveldb::Iterator *pcursor = NewIterator(); + boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator()); CDataStream ssKeySet(SER_DISK, CLIENT_VERSION); ssKeySet << make_pair('b', uint256(0)); @@ -224,7 +230,6 @@ bool CBlockTreeDB::LoadBlockIndexGuts() return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } } - delete pcursor; return true; } diff --git a/src/txdb.h b/src/txdb.h index 7d670c2542..f0b6b9e1dd 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -32,13 +32,13 @@ protected: public: CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); - bool GetCoins(const uint256 &txid, CCoins &coins); + bool GetCoins(const uint256 &txid, CCoins &coins) const; bool SetCoins(const uint256 &txid, const CCoins &coins); - bool HaveCoins(const uint256 &txid); - uint256 GetBestBlock(); + bool HaveCoins(const uint256 &txid) const; + uint256 GetBestBlock() const; bool SetBestBlock(const uint256 &hashBlock); - bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock); - bool GetStats(CCoinsStats &stats); + bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); + bool GetStats(CCoinsStats &stats) const; }; /** Access to the block database (blocks/index/) */ diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 29924fff09..238d5bab16 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -5,12 +5,14 @@ #include "core.h" #include "txmempool.h" +#include "util.h" #include <boost/circular_buffer.hpp> using namespace std; -CTxMemPoolEntry::CTxMemPoolEntry() +CTxMemPoolEntry::CTxMemPoolEntry(): + nFee(0), nTxSize(0), nTime(0), dPriority(0.0) { nHeight = MEMPOOL_HEIGHT; } @@ -344,7 +346,9 @@ public: }; -CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : minRelayFee(_minRelayFee) +CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : + nTransactionsUpdated(0), + minRelayFee(_minRelayFee) { // Sanity checks off by default for performance, because otherwise // accepting transactions becomes O(N^2) where N is the number @@ -402,6 +406,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry) for (unsigned int i = 0; i < tx.vin.size(); i++) mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); nTransactionsUpdated++; + totalTxSize += entry.GetTxSize(); } return true; } @@ -426,6 +431,8 @@ void CTxMemPool::remove(const CTransaction &tx, std::list<CTransaction>& removed removed.push_front(tx); BOOST_FOREACH(const CTxIn& txin, tx.vin) mapNextTx.erase(txin.prevout); + + totalTxSize -= mapTx[hash].GetTxSize(); mapTx.erase(hash); nTransactionsUpdated++; } @@ -477,19 +484,23 @@ void CTxMemPool::clear() LOCK(cs); mapTx.clear(); mapNextTx.clear(); + totalTxSize = 0; ++nTransactionsUpdated; } -void CTxMemPool::check(CCoinsViewCache *pcoins) const +void CTxMemPool::check(const CCoinsViewCache *pcoins) const { if (!fSanityCheck) return; LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); + uint64_t checkTotal = 0; + LOCK(cs); for (std::map<uint256, CTxMemPoolEntry>::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { unsigned int i = 0; + checkTotal += it->second.GetTxSize(); const CTransaction& tx = it->second.GetTx(); BOOST_FOREACH(const CTxIn &txin, tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. @@ -498,7 +509,7 @@ void CTxMemPool::check(CCoinsViewCache *pcoins) const const CTransaction& tx2 = it2->second.GetTx(); assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); } else { - CCoins &coins = pcoins->GetCoins(txin.prevout.hash); + const CCoins &coins = pcoins->GetCoins(txin.prevout.hash); assert(coins.IsAvailable(txin.prevout.n)); } // Check whether its inputs are marked in mapNextTx. @@ -518,6 +529,8 @@ void CTxMemPool::check(CCoinsViewCache *pcoins) const assert(tx.vin.size() > it->second.n); assert(it->first == it->second.ptx->vin[it->second.n].prevout); } + + assert(totalTxSize == checkTotal); } void CTxMemPool::queryHashes(vector<uint256>& vtxid) @@ -616,7 +629,7 @@ void CTxMemPool::ClearPrioritisation(const uint256 hash) CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } -bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) { +bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const { // If an entry in the mempool exists, always return that one, as it's guaranteed to never // conflict with the underlying cache, and it cannot have pruned entries (as it contains full) // transactions. First checking the underlying cache risks returning a pruned entry instead. @@ -628,7 +641,7 @@ bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) { return (base->GetCoins(txid, coins) && !coins.IsPruned()); } -bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) { +bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { return mempool.exists(txid) || base->HaveCoins(txid); } diff --git a/src/txmempool.h b/src/txmempool.h index 41b2c52f39..d95c4d970b 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -68,6 +68,7 @@ private: CMinerPolicyEstimator* minerPolicyEstimator; CFeeRate minRelayFee; // Passed to constructor to avoid dependency on main + uint64_t totalTxSize; // sum of all mempool tx' byte sizes public: mutable CCriticalSection cs; @@ -84,7 +85,7 @@ public: * all inputs are in the mapNextTx array). If sanity-checking is turned off, * check does nothing. */ - void check(CCoinsViewCache *pcoins) const; + void check(const CCoinsViewCache *pcoins) const; void setSanityCheck(bool _fSanityCheck) { fSanityCheck = _fSanityCheck; } bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry); @@ -108,6 +109,11 @@ public: LOCK(cs); return mapTx.size(); } + uint64_t GetTotalTxSize() + { + LOCK(cs); + return totalTxSize; + } bool exists(uint256 hash) { @@ -137,8 +143,8 @@ protected: public: CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn); - bool GetCoins(const uint256 &txid, CCoins &coins); - bool HaveCoins(const uint256 &txid); + bool GetCoins(const uint256 &txid, CCoins &coins) const; + bool HaveCoins(const uint256 &txid) const; }; #endif /* BITCOIN_TXMEMPOOL_H */ diff --git a/src/uint256.cpp b/src/uint256.cpp index 08c05594fd..feda0ca5a9 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -4,7 +4,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "uint256.h" -#include "util.h" + +#include "utilstrencodings.h" #include <stdio.h> #include <string.h> diff --git a/src/univalue/gen.cpp b/src/univalue/gen.cpp new file mode 100644 index 0000000000..881948f46e --- /dev/null +++ b/src/univalue/gen.cpp @@ -0,0 +1,78 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// +// To re-create univalue_escapes.h: +// $ g++ -o gen gen.cpp +// $ ./gen > univalue_escapes.h +// + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include "univalue.h" + +using namespace std; + +static bool initEscapes; +static const char *escapes[256]; + +static void initJsonEscape() +{ + escapes[(int)'"'] = "\\\""; + escapes[(int)'\\'] = "\\\\"; + escapes[(int)'/'] = "\\/"; + escapes[(int)'\b'] = "\\b"; + escapes[(int)'\f'] = "\\f"; + escapes[(int)'\n'] = "\\n"; + escapes[(int)'\r'] = "\\r"; + escapes[(int)'\t'] = "\\t"; + + initEscapes = true; +} + +static void outputEscape() +{ + printf( "// Automatically generated file. Do not modify.\n" + "#ifndef __UNIVALUE_ESCAPES_H__\n" + "#define __UNIVALUE_ESCAPES_H__\n" + "static const char *escapes[256] = {\n"); + + for (unsigned int i = 0; i < 256; i++) { + if (!escapes[i]) { + printf("\tNULL,\n"); + } else { + printf("\t\""); + + unsigned int si; + for (si = 0; si < strlen(escapes[i]); si++) { + char ch = escapes[i][si]; + switch (ch) { + case '"': + printf("\\\""); + break; + case '\\': + printf("\\\\"); + break; + default: + printf("%c", escapes[i][si]); + break; + } + } + + printf("\",\n"); + } + } + + printf( "};\n" + "#endif // __UNIVALUE_ESCAPES_H__\n"); +} + +int main (int argc, char *argv[]) +{ + initJsonEscape(); + outputEscape(); + return 0; +} + diff --git a/src/univalue/univalue.cpp b/src/univalue/univalue.cpp index afc208bffb..b0171e48c4 100644 --- a/src/univalue/univalue.cpp +++ b/src/univalue/univalue.cpp @@ -44,7 +44,7 @@ static bool validNumStr(const string& s) bool UniValue::setNumStr(const string& val_) { - if (!validNumStr(val)) + if (!validNumStr(val_)) return false; clear(); diff --git a/src/univalue/univalue_escapes.h b/src/univalue/univalue_escapes.h new file mode 100644 index 0000000000..1d3a70a968 --- /dev/null +++ b/src/univalue/univalue_escapes.h @@ -0,0 +1,262 @@ +// Automatically generated file. Do not modify. +#ifndef __UNIVALUE_ESCAPES_H__ +#define __UNIVALUE_ESCAPES_H__ +static const char *escapes[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\b", + "\\t", + "\\n", + NULL, + "\\f", + "\\r", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\\"", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\/", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\\\", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; +#endif // __UNIVALUE_ESCAPES_H__ diff --git a/src/univalue/univalue_write.cpp b/src/univalue/univalue_write.cpp index 1818f5c6f9..042091a827 100644 --- a/src/univalue/univalue_write.cpp +++ b/src/univalue/univalue_write.cpp @@ -5,33 +5,14 @@ #include <ctype.h> #include <stdio.h> #include "univalue.h" +#include "univalue_escapes.h" // TODO: Using UTF8 using namespace std; -static bool initEscapes; -static const char *escapes[256]; - -static void initJsonEscape() -{ - escapes['"'] = "\\\""; - escapes['\\'] = "\\\\"; - escapes['/'] = "\\/"; - escapes['\b'] = "\\b"; - escapes['\f'] = "\\f"; - escapes['\n'] = "\\n"; - escapes['\r'] = "\\r"; - escapes['\t'] = "\\t"; - - initEscapes = true; -} - static string json_escape(const string& inS) { - if (!initEscapes) - initJsonEscape(); - string outS; outS.reserve(inS.size() * 2); @@ -110,8 +91,11 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s if (prettyIndent) s += indentStr(prettyIndent, indentLevel); s += values[i].write(prettyIndent, indentLevel + 1); - if (i != (values.size() - 1)) - s += ", "; + if (i != (values.size() - 1)) { + s += ","; + if (prettyIndent) + s += " "; + } if (prettyIndent) s += "\n"; } @@ -130,7 +114,9 @@ void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, for (unsigned int i = 0; i < keys.size(); i++) { if (prettyIndent) s += indentStr(prettyIndent, indentLevel); - s += "\"" + json_escape(keys[i]) + "\": "; + s += "\"" + json_escape(keys[i]) + "\":"; + if (prettyIndent) + s += " "; s += values[i].write(prettyIndent, indentLevel + 1); if (i != (values.size() - 1)) s += ","; diff --git a/src/util.cpp b/src/util.cpp index ae2145a3a0..5a4e187f9e 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -11,14 +11,13 @@ #include "chainparamsbase.h" #include "random.h" +#include "serialize.h" #include "sync.h" -#include "uint256.h" -#include "version.h" +#include "utilstrencodings.h" +#include "utiltime.h" #include <stdarg.h> -#include <boost/date_time/posix_time/posix_time.hpp> - #ifndef WIN32 // for posix_fallocate #ifdef __linux__ @@ -76,6 +75,7 @@ #include <boost/foreach.hpp> #include <boost/program_options/detail/config_file.hpp> #include <boost/program_options/parsers.hpp> +#include <boost/thread.hpp> #include <openssl/crypto.h> #include <openssl/rand.h> @@ -244,148 +244,6 @@ int LogPrintStr(const std::string &str) return ret; } -string FormatMoney(int64_t n, bool fPlus) -{ - // Note: not using straight sprintf here because we do NOT want - // localized number formatting. - int64_t n_abs = (n > 0 ? n : -n); - int64_t quotient = n_abs/COIN; - int64_t remainder = n_abs%COIN; - string str = strprintf("%d.%08d", quotient, remainder); - - // Right-trim excess zeros before the decimal point: - int nTrim = 0; - for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i) - ++nTrim; - if (nTrim) - str.erase(str.size()-nTrim, nTrim); - - if (n < 0) - str.insert((unsigned int)0, 1, '-'); - else if (fPlus && n > 0) - str.insert((unsigned int)0, 1, '+'); - return str; -} - - -bool ParseMoney(const string& str, int64_t& nRet) -{ - return ParseMoney(str.c_str(), nRet); -} - -bool ParseMoney(const char* pszIn, int64_t& nRet) -{ - string strWhole; - int64_t nUnits = 0; - const char* p = pszIn; - while (isspace(*p)) - p++; - for (; *p; p++) - { - if (*p == '.') - { - p++; - int64_t nMult = CENT*10; - while (isdigit(*p) && (nMult > 0)) - { - nUnits += nMult * (*p++ - '0'); - nMult /= 10; - } - break; - } - if (isspace(*p)) - break; - if (!isdigit(*p)) - return false; - strWhole.insert(strWhole.end(), *p); - } - for (; *p; p++) - if (!isspace(*p)) - return false; - if (strWhole.size() > 10) // guard against 63 bit overflow - return false; - if (nUnits < 0 || nUnits > COIN) - return false; - int64_t nWhole = atoi64(strWhole); - int64_t nValue = nWhole*COIN + nUnits; - - nRet = nValue; - return true; -} - -// safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything -// even possibly remotely dangerous like & or > -static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@"); -string SanitizeString(const string& str) -{ - string strResult; - for (std::string::size_type i = 0; i < str.size(); i++) - { - if (safeChars.find(str[i]) != std::string::npos) - strResult.push_back(str[i]); - } - return strResult; -} - -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, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, - -1,0xa,0xb,0xc,0xd,0xe,0xf,-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,0xa,0xb,0xc,0xd,0xe,0xf,-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,-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,-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,-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,-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) - { - if (HexDigit(c) < 0) - return false; - } - return (str.size() > 0) && (str.size()%2 == 0); -} - -vector<unsigned char> ParseHex(const char* psz) -{ - // convert hex dump to vector - vector<unsigned char> vch; - while (true) - { - while (isspace(*psz)) - psz++; - signed char c = HexDigit(*psz++); - if (c == (signed char)-1) - break; - unsigned char n = (c << 4); - c = HexDigit(*psz++); - if (c == (signed char)-1) - break; - n |= c; - vch.push_back(n); - } - return vch; -} - -vector<unsigned char> ParseHex(const string& str) -{ - return ParseHex(str.c_str()); -} - static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet) { // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set @@ -483,334 +341,6 @@ bool SoftSetBoolArg(const std::string& strArg, bool fValue) return SoftSetArg(strArg, std::string("0")); } - -string EncodeBase64(const unsigned char* pch, size_t len) -{ - static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - string strRet=""; - strRet.reserve((len+2)/3*4); - - int mode=0, left=0; - const unsigned char *pchEnd = pch+len; - - while (pch<pchEnd) - { - int enc = *(pch++); - switch (mode) - { - case 0: // we have no bits - strRet += pbase64[enc >> 2]; - left = (enc & 3) << 4; - mode = 1; - break; - - case 1: // we have two bits - strRet += pbase64[left | (enc >> 4)]; - left = (enc & 15) << 2; - mode = 2; - break; - - case 2: // we have four bits - strRet += pbase64[left | (enc >> 6)]; - strRet += pbase64[enc & 63]; - mode = 0; - break; - } - } - - if (mode) - { - strRet += pbase64[left]; - strRet += '='; - if (mode == 1) - strRet += '='; - } - - return strRet; -} - -string EncodeBase64(const string& str) -{ - return EncodeBase64((const unsigned char*)str.c_str(), str.size()); -} - -vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid) -{ - static const int decode64_table[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, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, - -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, -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, -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, -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, -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, -1, -1, -1, -1, -1 - }; - - if (pfInvalid) - *pfInvalid = false; - - vector<unsigned char> vchRet; - vchRet.reserve(strlen(p)*3/4); - - int mode = 0; - int left = 0; - - while (1) - { - int dec = decode64_table[(unsigned char)*p]; - if (dec == -1) break; - p++; - switch (mode) - { - case 0: // we have no bits and get 6 - left = dec; - mode = 1; - break; - - case 1: // we have 6 bits and keep 4 - vchRet.push_back((left<<2) | (dec>>4)); - left = dec & 15; - mode = 2; - break; - - case 2: // we have 4 bits and get 6, we keep 2 - vchRet.push_back((left<<4) | (dec>>2)); - left = dec & 3; - mode = 3; - break; - - case 3: // we have 2 bits and get 6 - vchRet.push_back((left<<6) | dec); - mode = 0; - break; - } - } - - if (pfInvalid) - switch (mode) - { - case 0: // 4n base64 characters processed: ok - break; - - case 1: // 4n+1 base64 character processed: impossible - *pfInvalid = true; - break; - - case 2: // 4n+2 base64 characters processed: require '==' - if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1) - *pfInvalid = true; - break; - - case 3: // 4n+3 base64 characters processed: require '=' - if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1) - *pfInvalid = true; - break; - } - - return vchRet; -} - -string DecodeBase64(const string& str) -{ - vector<unsigned char> vchRet = DecodeBase64(str.c_str()); - return string((const char*)&vchRet[0], vchRet.size()); -} - -string EncodeBase32(const unsigned char* pch, size_t len) -{ - static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; - - string strRet=""; - strRet.reserve((len+4)/5*8); - - int mode=0, left=0; - const unsigned char *pchEnd = pch+len; - - while (pch<pchEnd) - { - int enc = *(pch++); - switch (mode) - { - case 0: // we have no bits - strRet += pbase32[enc >> 3]; - left = (enc & 7) << 2; - mode = 1; - break; - - case 1: // we have three bits - strRet += pbase32[left | (enc >> 6)]; - strRet += pbase32[(enc >> 1) & 31]; - left = (enc & 1) << 4; - mode = 2; - break; - - case 2: // we have one bit - strRet += pbase32[left | (enc >> 4)]; - left = (enc & 15) << 1; - mode = 3; - break; - - case 3: // we have four bits - strRet += pbase32[left | (enc >> 7)]; - strRet += pbase32[(enc >> 2) & 31]; - left = (enc & 3) << 3; - mode = 4; - break; - - case 4: // we have two bits - strRet += pbase32[left | (enc >> 5)]; - strRet += pbase32[enc & 31]; - mode = 0; - } - } - - static const int nPadding[5] = {0, 6, 4, 3, 1}; - if (mode) - { - strRet += pbase32[left]; - for (int n=0; n<nPadding[mode]; n++) - strRet += '='; - } - - return strRet; -} - -string EncodeBase32(const string& str) -{ - return EncodeBase32((const unsigned char*)str.c_str(), str.size()); -} - -vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid) -{ - static const int decode32_table[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, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, -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, -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, -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, -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, -1, -1, -1, -1, -1 - }; - - if (pfInvalid) - *pfInvalid = false; - - vector<unsigned char> vchRet; - vchRet.reserve((strlen(p))*5/8); - - int mode = 0; - int left = 0; - - while (1) - { - int dec = decode32_table[(unsigned char)*p]; - if (dec == -1) break; - p++; - switch (mode) - { - case 0: // we have no bits and get 5 - left = dec; - mode = 1; - break; - - case 1: // we have 5 bits and keep 2 - vchRet.push_back((left<<3) | (dec>>2)); - left = dec & 3; - mode = 2; - break; - - case 2: // we have 2 bits and keep 7 - left = left << 5 | dec; - mode = 3; - break; - - case 3: // we have 7 bits and keep 4 - vchRet.push_back((left<<1) | (dec>>4)); - left = dec & 15; - mode = 4; - break; - - case 4: // we have 4 bits, and keep 1 - vchRet.push_back((left<<4) | (dec>>1)); - left = dec & 1; - mode = 5; - break; - - case 5: // we have 1 bit, and keep 6 - left = left << 5 | dec; - mode = 6; - break; - - case 6: // we have 6 bits, and keep 3 - vchRet.push_back((left<<2) | (dec>>3)); - left = dec & 7; - mode = 7; - break; - - case 7: // we have 3 bits, and keep 0 - vchRet.push_back((left<<5) | dec); - mode = 0; - break; - } - } - - if (pfInvalid) - switch (mode) - { - case 0: // 8n base32 characters processed: ok - break; - - case 1: // 8n+1 base32 characters processed: impossible - case 3: // +3 - case 6: // +6 - *pfInvalid = true; - break; - - case 2: // 8n+2 base32 characters processed: require '======' - if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1) - *pfInvalid = true; - break; - - case 4: // 8n+4 base32 characters processed: require '====' - if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1) - *pfInvalid = true; - break; - - case 5: // 8n+5 base32 characters processed: require '===' - if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1) - *pfInvalid = true; - break; - - case 7: // 8n+7 base32 characters processed: require '=' - if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1) - *pfInvalid = true; - break; - } - - return vchRet; -} - -string DecodeBase32(const string& str) -{ - vector<unsigned char> vchRet = DecodeBase32(str.c_str()); - return string((const char*)&vchRet[0], vchRet.size()); -} - static std::string FormatException(std::exception* pex, const char* pszThread) { #ifdef WIN32 @@ -1102,45 +632,6 @@ void ShrinkDebugFile() fclose(file); } -static int64_t nMockTime = 0; // For unit testing - -int64_t GetTime() -{ - if (nMockTime) return nMockTime; - - return time(NULL); -} - -void SetMockTime(int64_t nMockTimeIn) -{ - nMockTime = nMockTimeIn; -} - -string FormatVersion(int nVersion) -{ - if (nVersion%100 == 0) - return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100); - else - return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100); -} - -string FormatFullVersion() -{ - return CLIENT_BUILD; -} - -// Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014) -std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments) -{ - std::ostringstream ss; - ss << "/"; - ss << name << ":" << FormatVersion(nClientVersion); - if (!comments.empty()) - ss << "(" << boost::algorithm::join(comments, "; ") << ")"; - ss << "/"; - return ss.str(); -} - #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) { @@ -1211,20 +702,6 @@ 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 @@ -1242,47 +719,15 @@ void SetupEnvironment() #endif } -std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime) +void SetThreadPriority(int nPriority) { - // 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(); +#ifdef WIN32 + SetThreadPriority(GetCurrentThread(), nPriority); +#else // WIN32 +#ifdef PRIO_THREAD + setpriority(PRIO_THREAD, 0, nPriority); +#else // PRIO_THREAD + setpriority(PRIO_PROCESS, 0, nPriority); +#endif // PRIO_THREAD +#endif // WIN32 } diff --git a/src/util.h b/src/util.h index db2005337b..30f7c15c89 100644 --- a/src/util.h +++ b/src/util.h @@ -3,6 +3,10 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +/** + * Server/client environment: argument handling, config file parsing, + * logging, thread wrappers + */ #ifndef BITCOIN_UTIL_H #define BITCOIN_UTIL_H @@ -11,84 +15,17 @@ #endif #include "compat.h" -#include "serialize.h" +#include "utiltime.h" #include "tinyformat.h" -#include <cstdio> #include <exception> #include <map> -#include <stdarg.h> #include <stdint.h> #include <string> -#include <utility> #include <vector> -#ifndef WIN32 -#include <sys/resource.h> -#include <sys/time.h> -#include <sys/types.h> -#endif - #include <boost/filesystem/path.hpp> -#include <boost/thread.hpp> - -class uint256; - -static const int64_t COIN = 100000000; -static const int64_t CENT = 1000000; - -#define BEGIN(a) ((char*)&(a)) -#define END(a) ((char*)&((&(a))[1])) -#define UBEGIN(a) ((unsigned char*)&(a)) -#define UEND(a) ((unsigned char*)&((&(a))[1])) -#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) - -// 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> - -// Align by increasing pointer, must have extra space at end of buffer -template <size_t nBytes, typename T> -T* alignup(T* p) -{ - union - { - T* ptr; - size_t n; - } u; - u.ptr = p; - u.n = (u.n + (nBytes-1)) & ~(nBytes-1); - return u.ptr; -} - -#ifdef WIN32 -#define MSG_DONTWAIT 0 - -#ifndef S_IRUSR -#define S_IRUSR 0400 -#define S_IWUSR 0200 -#endif -#else -#define MAX_PATH 1024 -#endif -// As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0 -#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) -#define MSG_NOSIGNAL 0 -#endif - -inline void MilliSleep(int64_t n) -{ -// Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50 -// until fixed in 1.52. Use the deprecated sleep method for the broken case. -// See: https://svn.boost.org/trac/boost/ticket/7238 -#if defined(HAVE_WORKING_BOOST_SLEEP_FOR) - boost::this_thread::sleep_for(boost::chrono::milliseconds(n)); -#elif defined(HAVE_WORKING_BOOST_SLEEP) - boost::this_thread::sleep(boost::posix_time::milliseconds(n)); -#else -//should never get here -#error missing boost sleep implementation -#endif -} +#include <boost/thread/exceptions.hpp> extern std::map<std::string, std::string> mapArgs; extern std::map<std::string, std::vector<std::string> > mapMultiArgs; @@ -108,7 +45,6 @@ bool LogAcceptCategory(const char* category); /* Send a string to the log output */ int LogPrintStr(const std::string &str); -#define strprintf tfm::format #define LogPrintf(...) LogPrint(NULL, __VA_ARGS__) /* When we switch to C++11, this can be switched to variadic templates instead @@ -147,22 +83,6 @@ static inline bool error(const char* format) } void PrintExceptionContinue(std::exception* pex, const char* pszThread); -std::string FormatMoney(int64_t n, bool fPlus=false); -bool ParseMoney(const std::string& str, int64_t& nRet); -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); -std::string EncodeBase64(const unsigned char* pch, size_t len); -std::string EncodeBase64(const std::string& str); -std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = NULL); -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[]); void FileCommit(FILE *fileout); bool TruncateFile(FILE *file, unsigned int length); @@ -183,111 +103,8 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif boost::filesystem::path GetTempPath(); void ShrinkDebugFile(); -int64_t GetTime(); -void SetMockTime(int64_t nMockTimeIn); -std::string FormatFullVersion(); -std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments); void runCommand(std::string strCommand); -inline std::string i64tostr(int64_t n) -{ - return strprintf("%d", n); -} - -inline std::string itostr(int n) -{ - return strprintf("%d", n); -} - -inline int64_t atoi64(const char* psz) -{ -#ifdef _MSC_VER - return _atoi64(psz); -#else - return strtoll(psz, NULL, 10); -#endif -} - -inline int64_t atoi64(const std::string& str) -{ -#ifdef _MSC_VER - return _atoi64(str.c_str()); -#else - return strtoll(str.c_str(), NULL, 10); -#endif -} - -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); -} - -inline int64_t roundint64(double d) -{ - return (int64_t)(d > 0 ? d + 0.5 : d - 0.5); -} - -inline int64_t abs64(int64_t n) -{ - return (n >= 0 ? n : -n); -} - -template<typename T> -std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) -{ - std::string rv; - static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - rv.reserve((itend-itbegin)*3); - for(T it = itbegin; it < itend; ++it) - { - unsigned char val = (unsigned char)(*it); - if(fSpaces && it != itbegin) - rv.push_back(' '); - rv.push_back(hexmap[val>>4]); - rv.push_back(hexmap[val&15]); - } - - return rv; -} - -template<typename T> -inline std::string HexStr(const T& vch, bool fSpaces=false) -{ - return HexStr(vch.begin(), vch.end(), fSpaces); -} - -/** 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 GetTimeMillis() -{ - return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - - boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds(); -} - -inline int64_t GetTimeMicros() -{ - return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - - boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds(); -} - -std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime); - inline bool IsSwitchChar(char c) { #ifdef WIN32 @@ -342,113 +159,9 @@ bool SoftSetArg(const std::string& strArg, const std::string& strValue); */ bool SoftSetBoolArg(const std::string& strArg, bool fValue); -/** - * Timing-attack-resistant comparison. - * Takes time proportional to length - * of first argument. - */ -template <typename T> -bool TimingResistantEqual(const T& a, const T& b) -{ - if (b.size() == 0) return a.size() == 0; - size_t accumulator = a.size() ^ b.size(); - for (size_t i = 0; i < a.size(); i++) - accumulator |= a[i] ^ b[i%b.size()]; - return accumulator == 0; -} - -/** Median filter over a stream of values. - * Returns the median of the last N numbers - */ -template <typename T> class CMedianFilter -{ -private: - std::vector<T> vValues; - std::vector<T> vSorted; - unsigned int nSize; -public: - CMedianFilter(unsigned int size, T initial_value): - nSize(size) - { - vValues.reserve(size); - vValues.push_back(initial_value); - vSorted = vValues; - } - - void input(T value) - { - if(vValues.size() == nSize) - { - vValues.erase(vValues.begin()); - } - vValues.push_back(value); - - vSorted.resize(vValues.size()); - std::copy(vValues.begin(), vValues.end(), vSorted.begin()); - std::sort(vSorted.begin(), vSorted.end()); - } - - T median() const - { - int size = vSorted.size(); - assert(size>0); - if(size & 1) // Odd number of elements - { - return vSorted[size/2]; - } - else // Even number of elements - { - return (vSorted[size/2-1] + vSorted[size/2]) / 2; - } - } - - int size() const - { - return vValues.size(); - } - - std::vector<T> sorted () const - { - return vSorted; - } -}; - -#ifdef WIN32 -inline void SetThreadPriority(int nPriority) -{ - SetThreadPriority(GetCurrentThread(), nPriority); -} -#else - -// PRIO_MAX is not defined on Solaris -#ifndef PRIO_MAX -#define PRIO_MAX 20 -#endif -#define THREAD_PRIORITY_LOWEST PRIO_MAX -#define THREAD_PRIORITY_BELOW_NORMAL 2 -#define THREAD_PRIORITY_NORMAL 0 -#define THREAD_PRIORITY_ABOVE_NORMAL (-2) - -inline void SetThreadPriority(int nPriority) -{ - // It's unclear if it's even possible to change thread priorities on Linux, - // but we really and truly need it for the generation threads. -#ifdef PRIO_THREAD - setpriority(PRIO_THREAD, 0, nPriority); -#else - setpriority(PRIO_PROCESS, 0, nPriority); -#endif -} -#endif - +void SetThreadPriority(int nPriority); void RenameThread(const char* name); -inline uint32_t ByteReverse(uint32_t value) -{ - value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); - return (value<<16) | (value>>16); -} - // Standard wrapper for do-something-forever thread functions. // "Forever" really means until the thread is interrupted. // Use it like: diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp new file mode 100644 index 0000000000..1bd48d8d4c --- /dev/null +++ b/src/utilmoneystr.cpp @@ -0,0 +1,75 @@ +#include "utilmoneystr.h" + +#include "core.h" +#include "tinyformat.h" + +using namespace std; + +string FormatMoney(int64_t n, bool fPlus) +{ + // Note: not using straight sprintf here because we do NOT want + // localized number formatting. + int64_t n_abs = (n > 0 ? n : -n); + int64_t quotient = n_abs/COIN; + int64_t remainder = n_abs%COIN; + string str = strprintf("%d.%08d", quotient, remainder); + + // Right-trim excess zeros before the decimal point: + int nTrim = 0; + for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i) + ++nTrim; + if (nTrim) + str.erase(str.size()-nTrim, nTrim); + + if (n < 0) + str.insert((unsigned int)0, 1, '-'); + else if (fPlus && n > 0) + str.insert((unsigned int)0, 1, '+'); + return str; +} + + +bool ParseMoney(const string& str, int64_t& nRet) +{ + return ParseMoney(str.c_str(), nRet); +} + +bool ParseMoney(const char* pszIn, int64_t& nRet) +{ + string strWhole; + int64_t nUnits = 0; + const char* p = pszIn; + while (isspace(*p)) + p++; + for (; *p; p++) + { + if (*p == '.') + { + p++; + int64_t nMult = CENT*10; + while (isdigit(*p) && (nMult > 0)) + { + nUnits += nMult * (*p++ - '0'); + nMult /= 10; + } + break; + } + if (isspace(*p)) + break; + if (!isdigit(*p)) + return false; + strWhole.insert(strWhole.end(), *p); + } + for (; *p; p++) + if (!isspace(*p)) + return false; + if (strWhole.size() > 10) // guard against 63 bit overflow + return false; + if (nUnits < 0 || nUnits > COIN) + return false; + int64_t nWhole = atoi64(strWhole); + int64_t nValue = nWhole*COIN + nUnits; + + nRet = nValue; + return true; +} diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h new file mode 100644 index 0000000000..f0c61aa138 --- /dev/null +++ b/src/utilmoneystr.h @@ -0,0 +1,19 @@ +// 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. + +/** + * Money parsing/formatting utilities. + */ +#ifndef BITCOIN_UTILMONEYSTR_H +#define BITCOIN_UTILMONEYSTR_H + +#include <stdint.h> +#include <string> + +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); + +#endif // BITCOIN_UTILMONEYSTR_H diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp new file mode 100644 index 0000000000..ef13555104 --- /dev/null +++ b/src/utilstrencodings.cpp @@ -0,0 +1,496 @@ +// 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 "utilstrencodings.h" + +#include "tinyformat.h" + +#include <boost/foreach.hpp> +#include <errno.h> +#include <limits> + +using namespace std; + +// safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything +// even possibly remotely dangerous like & or > +static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@"); +string SanitizeString(const string& str) +{ + string strResult; + for (std::string::size_type i = 0; i < str.size(); i++) + { + if (safeChars.find(str[i]) != std::string::npos) + strResult.push_back(str[i]); + } + return strResult; +} + +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, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-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,0xa,0xb,0xc,0xd,0xe,0xf,-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,-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,-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,-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,-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) + { + if (HexDigit(c) < 0) + return false; + } + return (str.size() > 0) && (str.size()%2 == 0); +} + +vector<unsigned char> ParseHex(const char* psz) +{ + // convert hex dump to vector + vector<unsigned char> vch; + while (true) + { + while (isspace(*psz)) + psz++; + signed char c = HexDigit(*psz++); + if (c == (signed char)-1) + break; + unsigned char n = (c << 4); + c = HexDigit(*psz++); + if (c == (signed char)-1) + break; + n |= c; + vch.push_back(n); + } + return vch; +} + +vector<unsigned char> ParseHex(const string& str) +{ + return ParseHex(str.c_str()); +} + +string EncodeBase64(const unsigned char* pch, size_t len) +{ + static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + string strRet=""; + strRet.reserve((len+2)/3*4); + + int mode=0, left=0; + const unsigned char *pchEnd = pch+len; + + while (pch<pchEnd) + { + int enc = *(pch++); + switch (mode) + { + case 0: // we have no bits + strRet += pbase64[enc >> 2]; + left = (enc & 3) << 4; + mode = 1; + break; + + case 1: // we have two bits + strRet += pbase64[left | (enc >> 4)]; + left = (enc & 15) << 2; + mode = 2; + break; + + case 2: // we have four bits + strRet += pbase64[left | (enc >> 6)]; + strRet += pbase64[enc & 63]; + mode = 0; + break; + } + } + + if (mode) + { + strRet += pbase64[left]; + strRet += '='; + if (mode == 1) + strRet += '='; + } + + return strRet; +} + +string EncodeBase64(const string& str) +{ + return EncodeBase64((const unsigned char*)str.c_str(), str.size()); +} + +vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid) +{ + static const int decode64_table[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, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, + -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, -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, -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, -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, -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, -1, -1, -1, -1, -1 + }; + + if (pfInvalid) + *pfInvalid = false; + + vector<unsigned char> vchRet; + vchRet.reserve(strlen(p)*3/4); + + int mode = 0; + int left = 0; + + while (1) + { + int dec = decode64_table[(unsigned char)*p]; + if (dec == -1) break; + p++; + switch (mode) + { + case 0: // we have no bits and get 6 + left = dec; + mode = 1; + break; + + case 1: // we have 6 bits and keep 4 + vchRet.push_back((left<<2) | (dec>>4)); + left = dec & 15; + mode = 2; + break; + + case 2: // we have 4 bits and get 6, we keep 2 + vchRet.push_back((left<<4) | (dec>>2)); + left = dec & 3; + mode = 3; + break; + + case 3: // we have 2 bits and get 6 + vchRet.push_back((left<<6) | dec); + mode = 0; + break; + } + } + + if (pfInvalid) + switch (mode) + { + case 0: // 4n base64 characters processed: ok + break; + + case 1: // 4n+1 base64 character processed: impossible + *pfInvalid = true; + break; + + case 2: // 4n+2 base64 characters processed: require '==' + if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1) + *pfInvalid = true; + break; + + case 3: // 4n+3 base64 characters processed: require '=' + if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1) + *pfInvalid = true; + break; + } + + return vchRet; +} + +string DecodeBase64(const string& str) +{ + vector<unsigned char> vchRet = DecodeBase64(str.c_str()); + return string((const char*)&vchRet[0], vchRet.size()); +} + +string EncodeBase32(const unsigned char* pch, size_t len) +{ + static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; + + string strRet=""; + strRet.reserve((len+4)/5*8); + + int mode=0, left=0; + const unsigned char *pchEnd = pch+len; + + while (pch<pchEnd) + { + int enc = *(pch++); + switch (mode) + { + case 0: // we have no bits + strRet += pbase32[enc >> 3]; + left = (enc & 7) << 2; + mode = 1; + break; + + case 1: // we have three bits + strRet += pbase32[left | (enc >> 6)]; + strRet += pbase32[(enc >> 1) & 31]; + left = (enc & 1) << 4; + mode = 2; + break; + + case 2: // we have one bit + strRet += pbase32[left | (enc >> 4)]; + left = (enc & 15) << 1; + mode = 3; + break; + + case 3: // we have four bits + strRet += pbase32[left | (enc >> 7)]; + strRet += pbase32[(enc >> 2) & 31]; + left = (enc & 3) << 3; + mode = 4; + break; + + case 4: // we have two bits + strRet += pbase32[left | (enc >> 5)]; + strRet += pbase32[enc & 31]; + mode = 0; + } + } + + static const int nPadding[5] = {0, 6, 4, 3, 1}; + if (mode) + { + strRet += pbase32[left]; + for (int n=0; n<nPadding[mode]; n++) + strRet += '='; + } + + return strRet; +} + +string EncodeBase32(const string& str) +{ + return EncodeBase32((const unsigned char*)str.c_str(), str.size()); +} + +vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid) +{ + static const int decode32_table[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, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, -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, -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, -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, -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, -1, -1, -1, -1, -1 + }; + + if (pfInvalid) + *pfInvalid = false; + + vector<unsigned char> vchRet; + vchRet.reserve((strlen(p))*5/8); + + int mode = 0; + int left = 0; + + while (1) + { + int dec = decode32_table[(unsigned char)*p]; + if (dec == -1) break; + p++; + switch (mode) + { + case 0: // we have no bits and get 5 + left = dec; + mode = 1; + break; + + case 1: // we have 5 bits and keep 2 + vchRet.push_back((left<<3) | (dec>>2)); + left = dec & 3; + mode = 2; + break; + + case 2: // we have 2 bits and keep 7 + left = left << 5 | dec; + mode = 3; + break; + + case 3: // we have 7 bits and keep 4 + vchRet.push_back((left<<1) | (dec>>4)); + left = dec & 15; + mode = 4; + break; + + case 4: // we have 4 bits, and keep 1 + vchRet.push_back((left<<4) | (dec>>1)); + left = dec & 1; + mode = 5; + break; + + case 5: // we have 1 bit, and keep 6 + left = left << 5 | dec; + mode = 6; + break; + + case 6: // we have 6 bits, and keep 3 + vchRet.push_back((left<<2) | (dec>>3)); + left = dec & 7; + mode = 7; + break; + + case 7: // we have 3 bits, and keep 0 + vchRet.push_back((left<<5) | dec); + mode = 0; + break; + } + } + + if (pfInvalid) + switch (mode) + { + case 0: // 8n base32 characters processed: ok + break; + + case 1: // 8n+1 base32 characters processed: impossible + case 3: // +3 + case 6: // +6 + *pfInvalid = true; + break; + + case 2: // 8n+2 base32 characters processed: require '======' + if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1) + *pfInvalid = true; + break; + + case 4: // 8n+4 base32 characters processed: require '====' + if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1) + *pfInvalid = true; + break; + + case 5: // 8n+5 base32 characters processed: require '===' + if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1) + *pfInvalid = true; + break; + + case 7: // 8n+7 base32 characters processed: require '=' + if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1) + *pfInvalid = true; + break; + } + + return vchRet; +} + +string DecodeBase32(const string& str) +{ + vector<unsigned char> vchRet = DecodeBase32(str.c_str()); + return string((const char*)&vchRet[0], vchRet.size()); +} + +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(); +} + +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(); +} + +std::string i64tostr(int64_t n) +{ + return strprintf("%d", n); +} + +std::string itostr(int n) +{ + return strprintf("%d", n); +} + +int64_t atoi64(const char* psz) +{ +#ifdef _MSC_VER + return _atoi64(psz); +#else + return strtoll(psz, NULL, 10); +#endif +} + +int64_t atoi64(const std::string& str) +{ +#ifdef _MSC_VER + return _atoi64(str.c_str()); +#else + return strtoll(str.c_str(), NULL, 10); +#endif +} + +int atoi(const std::string& str) +{ + return atoi(str.c_str()); +} diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h new file mode 100644 index 0000000000..0b8c1a1781 --- /dev/null +++ b/src/utilstrencodings.h @@ -0,0 +1,97 @@ +// 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. + +/** + * Utilities for converting data from/to strings. + */ +#ifndef BITCOIN_UTILSTRENCODINGS_H +#define BITCOIN_UTILSTRENCODINGS_H + +#include <stdint.h> +#include <string> +#include <vector> + +#define BEGIN(a) ((char*)&(a)) +#define END(a) ((char*)&((&(a))[1])) +#define UBEGIN(a) ((unsigned char*)&(a)) +#define UEND(a) ((unsigned char*)&((&(a))[1])) +#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) + +// 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> + +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); +std::string EncodeBase64(const unsigned char* pch, size_t len); +std::string EncodeBase64(const std::string& str); +std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = NULL); +std::string DecodeBase32(const std::string& str); +std::string EncodeBase32(const unsigned char* pch, size_t len); +std::string EncodeBase32(const std::string& str); + +std::string i64tostr(int64_t n); +std::string itostr(int n); +int64_t atoi64(const char* psz); +int64_t atoi64(const std::string& str); +int atoi(const std::string& 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); + +template<typename T> +std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) +{ + std::string rv; + static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + rv.reserve((itend-itbegin)*3); + for(T it = itbegin; it < itend; ++it) + { + unsigned char val = (unsigned char)(*it); + if(fSpaces && it != itbegin) + rv.push_back(' '); + rv.push_back(hexmap[val>>4]); + rv.push_back(hexmap[val&15]); + } + + return rv; +} + +template<typename T> +inline std::string HexStr(const T& vch, bool fSpaces=false) +{ + return HexStr(vch.begin(), vch.end(), fSpaces); +} + +/** 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); + +/** + * Timing-attack-resistant comparison. + * Takes time proportional to length + * of first argument. + */ +template <typename T> +bool TimingResistantEqual(const T& a, const T& b) +{ + if (b.size() == 0) return a.size() == 0; + size_t accumulator = a.size() ^ b.size(); + for (size_t i = 0; i < a.size(); i++) + accumulator |= a[i] ^ b[i%b.size()]; + return accumulator == 0; +} + +#endif // BITCOIN_UTILSTRENCODINGS_H diff --git a/src/utiltime.cpp b/src/utiltime.cpp new file mode 100644 index 0000000000..78f0342cba --- /dev/null +++ b/src/utiltime.cpp @@ -0,0 +1,66 @@ +// 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. + +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + +#include "utiltime.h" + +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/thread.hpp> + +using namespace std; + +static int64_t nMockTime = 0; // For unit testing + +int64_t GetTime() +{ + if (nMockTime) return nMockTime; + + return time(NULL); +} + +void SetMockTime(int64_t nMockTimeIn) +{ + nMockTime = nMockTimeIn; +} + +int64_t GetTimeMillis() +{ + return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - + boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds(); +} + +int64_t GetTimeMicros() +{ + return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - + boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds(); +} + +void MilliSleep(int64_t n) +{ +// Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50 +// until fixed in 1.52. Use the deprecated sleep method for the broken case. +// See: https://svn.boost.org/trac/boost/ticket/7238 +#if defined(HAVE_WORKING_BOOST_SLEEP_FOR) + boost::this_thread::sleep_for(boost::chrono::milliseconds(n)); +#elif defined(HAVE_WORKING_BOOST_SLEEP) + boost::this_thread::sleep(boost::posix_time::milliseconds(n)); +#else +//should never get here +#error missing boost sleep implementation +#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(); +} diff --git a/src/utiltime.h b/src/utiltime.h new file mode 100644 index 0000000000..500ae4dab9 --- /dev/null +++ b/src/utiltime.h @@ -0,0 +1,20 @@ +// 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_UTILTIME_H +#define BITCOIN_UTILTIME_H + +#include <stdint.h> +#include <string> + +int64_t GetTime(); +int64_t GetTimeMillis(); +int64_t GetTimeMicros(); +void SetMockTime(int64_t nMockTimeIn); +void MilliSleep(int64_t n); + +std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime); + +#endif diff --git a/src/version.cpp b/src/version.cpp index d86caa3ac2..8311041ed2 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -4,7 +4,10 @@ #include "version.h" +#include "tinyformat.h" + #include <string> +#include <boost/algorithm/string/join.hpp> // Name of client reported in the 'version' message. Report the same name // for both bitcoind and bitcoin-qt, to make it harder for attackers to @@ -69,3 +72,28 @@ const std::string CLIENT_NAME("Satoshi"); const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX); const std::string CLIENT_DATE(BUILD_DATE); + +static std::string FormatVersion(int nVersion) +{ + if (nVersion%100 == 0) + return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100); + else + return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100); +} + +std::string FormatFullVersion() +{ + return CLIENT_BUILD; +} + +// Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014) +std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments) +{ + std::ostringstream ss; + ss << "/"; + ss << name << ":" << FormatVersion(nClientVersion); + if (!comments.empty()) + ss << "(" << boost::algorithm::join(comments, "; ") << ")"; + ss << "/"; + return ss.str(); +} diff --git a/src/version.h b/src/version.h index 85c5dbf8d7..b87aa8258c 100644 --- a/src/version.h +++ b/src/version.h @@ -7,6 +7,7 @@ #include "clientversion.h" #include <string> +#include <vector> // // client versioning @@ -48,4 +49,7 @@ static const int BIP0031_VERSION = 60000; // "mempool" command, enhanced "getdata" behavior starts with this version static const int MEMPOOL_GD_VERSION = 60002; +std::string FormatFullVersion(); +std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments); + #endif diff --git a/src/wallet.cpp b/src/wallet.cpp index 7c04743c0f..786b2f6a92 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -10,8 +10,11 @@ #include "coincontrol.h" #include "net.h" #include "timedata.h" +#include "util.h" +#include "utilmoneystr.h" #include <boost/algorithm/string/replace.hpp> +#include <boost/thread.hpp> using namespace std; @@ -37,6 +40,11 @@ struct CompareValueOnly } }; +std::string COutput::ToString() const +{ + return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->vout[i].nValue).c_str()); +} + const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const { LOCK(cs_wallet); @@ -153,6 +161,7 @@ bool CWallet::AddWatchOnly(const CScript &dest) if (!CCryptoKeyStore::AddWatchOnly(dest)) return false; nTimeFirstKey = 1; // No birthday information for watch-only keys. + NotifyWatchonlyChanged(true); if (!fFileBacked) return true; return CWalletDB(strWalletFile).WriteWatchOnly(dest); @@ -2168,3 +2177,20 @@ bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, st } return false; } + +CKeyPool::CKeyPool() +{ + nTime = GetTime(); +} + +CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn) +{ + nTime = GetTime(); + vchPubKey = vchPubKeyIn; +} + +CWalletKey::CWalletKey(int64_t nExpires) +{ + nTimeCreated = (nExpires ? GetTime() : 0); + nTimeExpires = nExpires; +} diff --git a/src/wallet.h b/src/wallet.h index 73fcfa24e0..b3878adb1e 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -11,7 +11,6 @@ #include "keystore.h" #include "main.h" #include "ui_interface.h" -#include "util.h" #include "walletdb.h" #include <algorithm> @@ -61,16 +60,8 @@ public: int64_t nTime; CPubKey vchPubKey; - CKeyPool() - { - nTime = GetTime(); - } - - CKeyPool(const CPubKey& vchPubKeyIn) - { - nTime = GetTime(); - vchPubKey = vchPubKeyIn; - } + CKeyPool(); + CKeyPool(const CPubKey& vchPubKeyIn); IMPLEMENT_SERIALIZE ( @@ -408,6 +399,9 @@ public: /** Show progress e.g. for rescan */ boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress; + + /** Watch-only address added */ + boost::signals2::signal<void (bool fHaveWatchOnly)> NotifyWatchonlyChanged; }; /** A key allocated from the key pool. */ @@ -820,15 +814,7 @@ public: tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; } - std::string ToString() const - { - 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()); - } + std::string ToString() const; }; @@ -845,11 +831,7 @@ public: //// todo: add something to note what created it (user, getnewaddress, change) //// maybe should have a map<string, string> property map - CWalletKey(int64_t nExpires=0) - { - nTimeCreated = (nExpires ? GetTime() : 0); - nTimeExpires = nExpires; - } + CWalletKey(int64_t nExpires=0); IMPLEMENT_SERIALIZE ( @@ -858,7 +840,7 @@ public: READWRITE(vchPrivKey); READWRITE(nTimeCreated); READWRITE(nTimeExpires); - READWRITE(strComment); + READWRITE(LIMITED_STRING(strComment, 65536)); ) }; @@ -923,6 +905,7 @@ public: strOtherAccount.clear(); strComment.clear(); nOrderPos = -1; + nEntryNo = 0; } IMPLEMENT_SERIALIZE @@ -933,7 +916,7 @@ public: // Note: strAccount is serialized as part of the key, not here. READWRITE(nCreditDebit); READWRITE(nTime); - READWRITE(strOtherAccount); + READWRITE(LIMITED_STRING(strOtherAccount, 65536)); if (!fRead) { @@ -949,7 +932,7 @@ public: } } - READWRITE(strComment); + READWRITE(LIMITED_STRING(strComment, 65536)); size_t nSepPos = strComment.find("\0", 0, 1); if (fRead) diff --git a/src/walletdb.cpp b/src/walletdb.cpp index a95baf83d0..2fa6071658 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -9,10 +9,13 @@ #include "protocol.h" #include "serialize.h" #include "sync.h" +#include "utiltime.h" +#include "util.h" #include "wallet.h" #include <boost/filesystem.hpp> #include <boost/foreach.hpp> +#include <boost/thread.hpp> using namespace std; using namespace boost; |