diff options
78 files changed, 1390 insertions, 422 deletions
diff --git a/.travis.yml b/.travis.yml index bc2c7faf7e..f5e306f0a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -72,10 +72,8 @@ script: - 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 - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./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) + - mkdir build && cd build + - ../configure $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) - make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false ) - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS check VERBOSE=1; fi diff --git a/Makefile.am b/Makefile.am index 5783c1fdd8..b10d085066 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,7 +28,7 @@ OSX_DSSTORE_GEN=$(top_srcdir)/contrib/macdeploy/custom_dsstore.py OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns -OSX_PLIST=$(top_srcdir)/share/qt/Info.plist #not installed +OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md) @@ -53,18 +53,8 @@ COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \ leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info dist-hook: - -$(MAKE) -C $(top_distdir)/src/leveldb clean - -$(MAKE) -C $(top_distdir)/src/secp256k1 distclean -$(GIT) archive --format=tar HEAD -- src/clientversion.cpp | $(AMTAR) -C $(top_distdir) -xf - -distcheck-hook: - $(MKDIR_P) $(top_distdir)/_build/src/leveldb - cp -rf $(top_srcdir)/src/leveldb/* $(top_distdir)/_build/src/leveldb/ - -$(MAKE) -C $(top_distdir)/_build/src/leveldb clean - -distcleancheck: - @: - $(BITCOIN_WIN_INSTALLER): all-recursive $(MKDIR_P) $(top_builddir)/release STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIND_BIN) $(top_builddir)/release @@ -234,7 +224,11 @@ EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.py qa/rpc- CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) +# This file is problematic for out-of-tree builds if it exists. +DISTCLEANFILES = qa/pull-tester/tests_config.pyc + .INTERMEDIATE: $(COVERAGE_INFO) clean-local: rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ qa/tmp/ cache/ $(OSX_APP) + rm -rf qa/pull-tester/__pycache__ diff --git a/configure.ac b/configure.ac index a1c04daf53..7f9ff20cd7 100644 --- a/configure.ac +++ b/configure.ac @@ -1060,6 +1060,7 @@ AC_SUBST(MINIUPNPC_LIBS) AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py]) AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh]) AC_CONFIG_FILES([qa/pull-tester/tests_config.py],[chmod +x qa/pull-tester/tests_config.py]) +AC_CONFIG_LINKS([qa/pull-tester/rpc-tests.py:qa/pull-tester/rpc-tests.py]) dnl boost's m4 checks do something really nasty: they export these vars. As a dnl result, they leak into secp256k1's configure and crazy things happen. diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 13941f5d55..cd289b2f6e 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -5,7 +5,7 @@ suites: - "trusty" architectures: - "amd64" -packages: +packages: - "curl" - "g++-multilib" - "git-core" @@ -18,7 +18,6 @@ packages: - "binutils-gold" - "ca-certificates" - "python" -reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin.git" "dir": "bitcoin" @@ -26,9 +25,12 @@ files: [] script: | WRAP_DIR=$HOME/wrapped HOSTS="i686-pc-linux-gnu x86_64-unknown-linux-gnu" - CONFIGFLAGS="--enable-glibc-back-compat --enable-reduce-exports --disable-bench --disable-gui-tests LDFLAGS=-static-libstdc++" + CONFIGFLAGS="--enable-glibc-back-compat --enable-reduce-exports --disable-bench --disable-gui-tests" FAKETIME_HOST_PROGS="" - FAKETIME_PROGS="date ar ranlib nm strip" + FAKETIME_PROGS="date ar ranlib nm strip objcopy" + HOST_CFLAGS="-O2 -g" + HOST_CXXFLAGS="-O2 -g" + HOST_LDFLAGS=-static-libstdc++ export QT_RCC_TEST=1 export GZIP="-9n" @@ -42,29 +44,36 @@ script: | mkdir -p ${BASE_CACHE} ${SOURCES_PATH} fi - # Create global faketime wrappers + function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} done + } - # Create per-host faketime wrappers + function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done + } + export PATH=${WRAP_DIR}:${PATH} + # Faketime for depends so intermediate results are comparable + create_global_faketime_wrappers "2000-01-01 12:00:00" + create_per-host_faketime_wrappers "2000-01-01 12:00:00" + cd bitcoin BASEPREFIX=`pwd`/depends # Build dependencies for each host @@ -72,9 +81,13 @@ script: | make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" done + # Faketime for binaries + create_global_faketime_wrappers "${REFERENCE_DATETIME}" + create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" + # Create the release tarball using (arbitrarily) the first host ./autogen.sh - ./configure --prefix=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'` + CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist SOURCEDIST=`echo bitcoin-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` @@ -95,20 +108,26 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST - ./configure --prefix=${BASEPREFIX}/${i} --bindir=${INSTALLPATH}/bin --includedir=${INSTALLPATH}/include --libdir=${INSTALLPATH}/lib --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" LDFLAGS="${HOST_LDFLAGS}" make ${MAKEOPTS} make ${MAKEOPTS} -C src check-security make ${MAKEOPTS} -C src check-symbols - make install-strip + make install DESTDIR=${INSTALLPATH} cd installed find . -name "lib*.la" -delete find . -name "lib*.a" -delete rm -rf ${DISTNAME}/lib/pkgconfig - find ${DISTNAME} | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz + find ${DISTNAME}/bin -type f -executable -exec objcopy --only-keep-debug {} {}.dbg \; -exec strip -s {} \; -exec objcopy --add-gnu-debuglink={}.dbg {} \; + find ${DISTNAME}/lib -type f -exec objcopy --only-keep-debug {} {}.dbg \; -exec strip -s {} \; -exec objcopy --add-gnu-debuglink={}.dbg {} \; + find ${DISTNAME} -not -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz + find ${DISTNAME} -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}-debug.tar.gz cd ../../ + rm -rf distsrc-${i} done mkdir -p $OUTDIR/src mv $SOURCEDIST $OUTDIR/src + mv ${OUTDIR}/${DISTNAME}-x86_64-*-debug.tar.gz ${OUTDIR}/${DISTNAME}-linux64-debug.tar.gz + mv ${OUTDIR}/${DISTNAME}-i686-*-debug.tar.gz ${OUTDIR}/${DISTNAME}-linux32-debug.tar.gz mv ${OUTDIR}/${DISTNAME}-x86_64-*.tar.gz ${OUTDIR}/${DISTNAME}-linux64.tar.gz mv ${OUTDIR}/${DISTNAME}-i686-*.tar.gz ${OUTDIR}/${DISTNAME}-linux32.tar.gz diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml index fac61aa3de..f6e9414ab1 100644 --- a/contrib/gitian-descriptors/gitian-osx-signer.yml +++ b/contrib/gitian-descriptors/gitian-osx-signer.yml @@ -6,7 +6,6 @@ architectures: - "amd64" packages: - "faketime" -reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin-core/bitcoin-detached-sigs.git" "dir": "signature" @@ -34,5 +33,5 @@ script: | tar -xf ${UNSIGNED} OSX_VOLNAME="$(cat osx_volname)" ./detached-sig-apply.sh ${UNSIGNED} signature/osx - ${WRAP_DIR}/genisoimage -no-cache-inodes -D -l -probe -V "${OSX_VOLNAME}" -no-pad -r -apple -o uncompressed.dmg signed-app + ${WRAP_DIR}/genisoimage -no-cache-inodes -D -l -probe -V "${OSX_VOLNAME}" -no-pad -r -dir-mode 0755 -apple -o uncompressed.dmg signed-app ${WRAP_DIR}/dmg dmg uncompressed.dmg ${OUTDIR}/${SIGNED} diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index c430932f9d..8436cd612a 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -5,7 +5,7 @@ suites: - "trusty" architectures: - "amd64" -packages: +packages: - "ca-certificates" - "curl" - "g++" @@ -27,7 +27,6 @@ packages: - "python-dev" - "python-setuptools" - "fonts-tuffy" -reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin.git" "dir": "bitcoin" @@ -54,29 +53,36 @@ script: | export ZERO_AR_DATE=1 - # Create global faketime wrappers + function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} done + } - # Create per-host faketime wrappers + function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done + } + export PATH=${WRAP_DIR}:${PATH} + # Faketime for depends so intermediate results are comparable + create_global_faketime_wrappers "2000-01-01 12:00:00" + create_per-host_faketime_wrappers "2000-01-01 12:00:00" + cd bitcoin BASEPREFIX=`pwd`/depends @@ -88,9 +94,13 @@ script: | make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" done + # Faketime for binaries + create_global_faketime_wrappers "${REFERENCE_DATETIME}" + create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" + # Create the release tarball using (arbitrarily) the first host ./autogen.sh - ./configure --prefix=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'` + CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist SOURCEDIST=`echo bitcoin-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` @@ -112,9 +122,9 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST - ./configure --prefix=${BASEPREFIX}/${i} --bindir=${INSTALLPATH}/bin --includedir=${INSTALLPATH}/include --libdir=${INSTALLPATH}/lib --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} make ${MAKEOPTS} - make install-strip + make install-strip DESTDIR=${INSTALLPATH} make osx_volname make deploydir diff --git a/contrib/gitian-descriptors/gitian-win-signer.yml b/contrib/gitian-descriptors/gitian-win-signer.yml index 88edb96627..3c1e0214a0 100644 --- a/contrib/gitian-descriptors/gitian-win-signer.yml +++ b/contrib/gitian-descriptors/gitian-win-signer.yml @@ -7,7 +7,6 @@ architectures: packages: - "libssl-dev" - "autoconf" -reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin-core/bitcoin-detached-sigs.git" "dir": "signature" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 9f7322f0b5..1d3a876dfb 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -5,7 +5,7 @@ suites: - "trusty" architectures: - "amd64" -packages: +packages: - "curl" - "g++" - "git-core" @@ -21,7 +21,6 @@ packages: - "zip" - "ca-certificates" - "python" -reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin.git" "dir": "bitcoin" @@ -29,9 +28,11 @@ files: [] script: | WRAP_DIR=$HOME/wrapped HOSTS="x86_64-w64-mingw32 i686-w64-mingw32" - CONFIGFLAGS="--enable-reduce-exports --disable-gui-tests" - FAKETIME_HOST_PROGS="g++ ar ranlib nm windres strip" + CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests" + FAKETIME_HOST_PROGS="g++ ar ranlib nm windres strip objcopy" FAKETIME_PROGS="date makensis zip" + HOST_CFLAGS="-O2 -g" + HOST_CXXFLAGS="-O2 -g" export QT_RCC_TEST=1 export GZIP="-9n" @@ -45,29 +46,31 @@ script: | mkdir -p ${BASE_CACHE} ${SOURCES_PATH} fi - # Create global faketime wrappers + function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} done + } - # Create per-host faketime wrappers + function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done + } - # Create per-host linker wrapper + function create_per-host_linker_wrapper { # This is only needed for trusty, as the mingw linker leaks a few bytes of # heap, causing non-determinism. See discussion in https://github.com/bitcoin/bitcoin/pull/6900 for i in $HOSTS; do @@ -83,15 +86,21 @@ script: | echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "export COMPILER_PATH=${WRAP_DIR}/${i}" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done + } export PATH=${WRAP_DIR}:${PATH} + # Faketime for depends so intermediate results are comparable + create_global_faketime_wrappers "2000-01-01 12:00:00" + create_per-host_faketime_wrappers "2000-01-01 12:00:00" + create_per-host_linker_wrapper "2000-01-01 12:00:00" + cd bitcoin BASEPREFIX=`pwd`/depends # Build dependencies for each host @@ -99,9 +108,14 @@ script: | make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" done + # Faketime for binaries + create_global_faketime_wrappers "${REFERENCE_DATETIME}" + create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" + create_per-host_linker_wrapper "${REFERENCE_DATETIME}" + # Create the release tarball using (arbitrarily) the first host ./autogen.sh - ./configure --prefix=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'` + CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist SOURCEDIST=`echo bitcoin-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` @@ -125,22 +139,28 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST - ./configure --prefix=${BASEPREFIX}/${i} --bindir=${INSTALLPATH}/bin --includedir=${INSTALLPATH}/include --libdir=${INSTALLPATH}/lib --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" make ${MAKEOPTS} make ${MAKEOPTS} -C src check-security make deploy - make install-strip + make install DESTDIR=${INSTALLPATH} cp -f bitcoin-*setup*.exe $OUTDIR/ cd installed mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/ find . -name "lib*.la" -delete find . -name "lib*.a" -delete rm -rf ${DISTNAME}/lib/pkgconfig - find ${DISTNAME} -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}.zip - cd ../.. + find ${DISTNAME}/bin -type f -executable -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; + find ${DISTNAME}/lib -type f -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; + find ${DISTNAME} -not -name "*.dbg" -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}.zip + find ${DISTNAME} -name "*.dbg" -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}-debug.zip + cd ../../ + rm -rf distsrc-${i} done cd $OUTDIR rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe find . -name "*-setup-unsigned.exe" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz + mv ${OUTDIR}/${DISTNAME}-x86_64-*-debug.zip ${OUTDIR}/${DISTNAME}-win64-debug.zip + mv ${OUTDIR}/${DISTNAME}-i686-*-debug.zip ${OUTDIR}/${DISTNAME}-win32-debug.zip mv ${OUTDIR}/${DISTNAME}-x86_64-*.zip ${OUTDIR}/${DISTNAME}-win64.zip mv ${OUTDIR}/${DISTNAME}-i686-*.zip ${OUTDIR}/${DISTNAME}-win32.zip diff --git a/contrib/gitian-keys/luke-jr-key.pgp b/contrib/gitian-keys/luke-jr-key.pgp Binary files differindex 4406e6d5be..a2d34e75e1 100644 --- a/contrib/gitian-keys/luke-jr-key.pgp +++ b/contrib/gitian-keys/luke-jr-key.pgp diff --git a/depends/config.guess b/depends/config.guess index 373a659a06..c4bd827a7b 100755 --- a/depends/config.guess +++ b/depends/config.guess @@ -2,7 +2,7 @@ # Attempt to guess a canonical system name. # Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2016-02-11' +timestamp='2016-05-15' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -186,9 +186,12 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. + # to ELF recently (or will in the future) and ABI. case "${UNAME_MACHINE_ARCH}" in - arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax) + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ @@ -386,7 +389,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # This test works for both compilers. if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 @@ -684,7 +687,7 @@ EOF exit (0); } EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac @@ -701,7 +704,7 @@ EOF # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w @@ -900,7 +903,7 @@ EOF exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix @@ -1276,6 +1279,9 @@ EOF SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; @@ -1291,7 +1297,7 @@ EOF if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in @@ -1386,7 +1392,7 @@ EOF echo i386-pc-xenix exit ;; i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos @@ -1405,18 +1411,17 @@ esac cat >&2 <<EOF $0: unable to guess system type -This script, last modified $timestamp, has failed to recognize -the operating system you are using. It is advised that you -download the most up to date version of the config scripts from +This script (version $timestamp), has failed to recognize the +operating system you are using. If your script is old, overwrite +config.guess and config.sub with the latest versions from: http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess and http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub -If the version you run ($0) is already up to date, please -send the following data and any information you think might be -pertinent to <config-patches@gnu.org> in order to provide the needed -information to handle your system. +If $0 has already been updated, send the following data and any +information you think might be pertinent to config-patches@gnu.org to +provide the necessary information to handle your system. config.guess timestamp = $timestamp diff --git a/depends/config.site.in b/depends/config.site.in index 984ddb1e62..e731537bf7 100644 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -1,24 +1,26 @@ +depends_prefix="`dirname ${ac_site_file}`/.." + cross_compiling=maybe host_alias=@HOST@ ac_tool_prefix=${host_alias}- if test -z $with_boost; then - with_boost=$prefix + with_boost=$depends_prefix fi if test -z $with_qt_plugindir; then - with_qt_plugindir=$prefix/plugins + with_qt_plugindir=$depends_prefix/plugins fi if test -z $with_qt_translationdir; then - with_qt_translationdir=$prefix/translations + with_qt_translationdir=$depends_prefix/translations fi if test -z $with_qt_bindir; then - with_qt_bindir=$prefix/native/bin + with_qt_bindir=$depends_prefix/native/bin fi if test -z $with_protoc_bindir; then - with_protoc_bindir=$prefix/native/bin + with_protoc_bindir=$depends_prefix/native/bin fi if test -z $with_comparison_tool; then - with_comparison_tool=$prefix/native/share/BitcoindComparisonTool_jar/BitcoindComparisonTool.jar + with_comparison_tool=$depends_prefix/native/share/BitcoindComparisonTool_jar/BitcoindComparisonTool.jar fi @@ -41,32 +43,32 @@ fi if test x@host_os@ = xmingw32; then if test -z $with_qt_incdir; then - with_qt_incdir=$prefix/include + with_qt_incdir=$depends_prefix/include fi if test -z $with_qt_libdir; then - with_qt_libdir=$prefix/lib + with_qt_libdir=$depends_prefix/lib fi fi -PATH=$prefix/native/bin:$PATH +PATH=$depends_prefix/native/bin:$PATH PKG_CONFIG="`which pkg-config` --static" # These two need to remain exported because pkg-config does not see them # otherwise. That means they must be unexported at the end of configure.ac to # avoid ruining the cache. Sigh. -export PKG_CONFIG_LIBDIR=$prefix/lib/pkgconfig -export PKG_CONFIG_PATH=$prefix/share/pkgconfig +export PKG_CONFIG_LIBDIR=$depends_prefix/lib/pkgconfig +export PKG_CONFIG_PATH=$depends_prefix/share/pkgconfig -CPPFLAGS="-I$prefix/include/ $CPPFLAGS" -LDFLAGS="-L$prefix/lib $LDFLAGS" +CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS" +LDFLAGS="-L$depends_prefix/lib $LDFLAGS" CC="@CC@" CXX="@CXX@" OBJC="${CC}" OBJCXX="${CXX}" -CCACHE=$prefix/native/bin/ccache -PYTHONPATH=$prefix/native/lib/python/dist-packages:$PYTHONPATH +CCACHE=$depends_prefix/native/bin/ccache +PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH if test -n "@AR@"; then AR=@AR@ diff --git a/depends/config.sub b/depends/config.sub index 6223dde931..6d86a1e2f7 100755 --- a/depends/config.sub +++ b/depends/config.sub @@ -2,7 +2,7 @@ # Configuration validation subroutine script. # Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2016-01-01' +timestamp='2016-05-10' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -1399,7 +1399,7 @@ case $os in | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ - | -onefs* | -tirtos*) + | -onefs* | -tirtos* | -phoenix*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1531,6 +1531,8 @@ case $os in ;; -nacl*) ;; + -ios) + ;; -none) ;; *) diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk index 1ac4435374..bd29275638 100644 --- a/depends/packages/expat.mk +++ b/depends/packages/expat.mk @@ -1,8 +1,8 @@ package=expat -$(package)_version=2.1.0 -$(package)_download_path=http://sourceforge.net/projects/expat/files/expat/$($(package)_version) -$(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=823705472f816df21c8f6aa026dd162b280806838bb55b3432b0fb1fcca7eb86 +$(package)_version=2.1.1 +$(package)_download_path=https://downloads.sourceforge.net/project/expat/expat/$($(package)_version) +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=aff584e5a2f759dcfc6d48671e9529f6afe1e30b0cd6a4cec200cbe3f793de67 define $(package)_set_vars $(package)_config_opts=--disable-static diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk index f7d6e0f9fc..7cea28ff0b 100644 --- a/depends/packages/freetype.mk +++ b/depends/packages/freetype.mk @@ -1,8 +1,8 @@ package=freetype -$(package)_version=2.5.3 -$(package)_download_path=http://downloads.sourceforge.net/$(package) +$(package)_version=2.6.3 +$(package)_download_path=http://download.savannah.gnu.org/releases/$(package) $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=c0848b29d52ef3ca27ad92e08351f023c5e24ce8cea7d8fe69fc96358e65f75e +$(package)_sha256_hash=371e707aa522acf5b15ce93f11183c725b8ed1ee8546d7b3af549863045863a2 define $(package)_set_vars $(package)_config_opts=--without-zlib --without-png --disable-static diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk index 45fa03631f..e34cf7be2f 100644 --- a/depends/packages/miniupnpc.mk +++ b/depends/packages/miniupnpc.mk @@ -1,8 +1,8 @@ package=miniupnpc -$(package)_version=1.9.20160209 +$(package)_version=2.0 $(package)_download_path=http://miniupnp.free.fr/files $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=572171eacc1d72537ce47b6f4571260757ab7bcfdaf54c3a55c7f88594d94b6f +$(package)_sha256_hash=d434ceb8986efbe199c5ca53f90ed53eab290b1e6d0530b717eb6fa49d61f93b define $(package)_set_vars $(package)_build_opts=CC="$($(package)_cc)" diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk index cc76f9a794..9216e17598 100644 --- a/depends/packages/native_ccache.mk +++ b/depends/packages/native_ccache.mk @@ -1,8 +1,8 @@ package=native_ccache -$(package)_version=3.2.4 +$(package)_version=3.2.5 $(package)_download_path=http://samba.org/ftp/ccache $(package)_file_name=ccache-$($(package)_version).tar.bz2 -$(package)_sha256_hash=ffeb967edb549e67da0bd5f44f729a2022de9fdde65dfd80d2a7204d7f75332e +$(package)_sha256_hash=7a553809e90faf9de3a23ee9c5b5f786cfd4836bf502744bedb824a24bee1097 define $(package)_set_vars $(package)_config_opts= diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index b3f18db056..f8901f72c2 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -1,11 +1,11 @@ package=zeromq -$(package)_version=4.0.7 +$(package)_version=4.1.4 $(package)_download_path=http://download.zeromq.org $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=e00b2967e074990d0538361cc79084a0a92892df2c6e7585da34e4c61ee47b03 +$(package)_sha256_hash=e99f44fde25c2e4cb84ce440f87ca7d3fe3271c2b8cfbc67d55e4de25e6fe378 define $(package)_set_vars - $(package)_config_opts=--without-documentation --disable-shared + $(package)_config_opts=--without-documentation --disable-shared --without-libsodium $(package)_config_opts_linux=--with-pic $(package)_cxxflags=-std=c++11 endef @@ -15,11 +15,11 @@ define $(package)_config_cmds endef define $(package)_build_cmds - $(MAKE) -C src + $(MAKE) libzmq.la endef define $(package)_stage_cmds - $(MAKE) -C src DESTDIR=$($(package)_staging_dir) install + $(MAKE) DESTDIR=$($(package)_staging_dir) install-libLTLIBRARIES install-includeHEADERS install-pkgconfigDATA endef define $(package)_postprocess_cmds diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 94bd86203e..95c46b05fe 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -322,7 +322,7 @@ Strings and formatting buffer overflows and surprises with `\0` characters. Also some C string manipulations tend to act differently depending on platform, or even the user locale -- Use `ParseInt32`, `ParseInt64`, `ParseDouble` from `utilstrencodings.h` for number parsing +- Use `ParseInt32`, `ParseInt64`, `ParseUInt32`, `ParseUInt64`, `ParseDouble` from `utilstrencodings.h` for number parsing - *Rationale*: These functions do overflow checking, and avoid pesky locale issues @@ -380,3 +380,51 @@ GUI - *Rationale*: Model classes pass through events and data from the core, they should not interact with the user. That's where View classes come in. The converse also holds: try to not directly access core data structures from Views. + +Git and github tips +--------------------- + +- For resolving merge/rebase conflicts, it can be useful to enable diff3 style using + `git config merge.conflictstyle diff3`. Instead of + + <<< + yours + === + theirs + >>> + + you will see + + <<< + yours + ||| + original + === + theirs + >>> + + This may make it much clearer what caused the conflict. In this style, you can often just look + at what changed between *original* and *theirs*, and mechanically apply that to *yours* (or the other way around). + +- When reviewing patches which change indentation in C++ files, use `git diff -w` and `git show -w`. This makes + the diff algorithm ignore whitespace changes. This feature is also available on github.com, by adding `?w=1` + at the end of any URL which shows a diff. + +- When reviewing patches that change symbol names in many places, use `git diff --word-diff`. This will instead + of showing the patch as deleted/added *lines*, show deleted/added *words*. + +- When reviewing patches that move code around, try using + `git diff --patience commit~:old/file.cpp commit:new/file/name.cpp`, and ignoring everything except the + moved body of code which should show up as neither `+` or `-` lines. In case it was not a pure move, this may + even work when combined with the `-w` or `--word-diff` options described above. + +- When looking at other's pull requests, it may make sense to add the following section to your `.git/config` + file: + + [remote "upstream-pull"] + fetch = +refs/pull/*:refs/remotes/upstream-pull/* + url = git@github.com:bitcoin/bitcoin.git + + This will add an `upstream-pull` remote to your git repository, which can be fetched using `git fetch --all` + or `git fetch upstream-pull`. Afterwards, you can use `upstream-pull/NUMBER/head` in arguments to `git show`, + `git checkout` and anywhere a commit id would be acceptable to see the changes from pull request NUMBER. diff --git a/doc/release-notes.md b/doc/release-notes.md index 7d44b8cda9..be619e41c6 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -80,6 +80,13 @@ The following outputs are affected by this change: - REST `/rest/block/` (JSON format when including extended tx details) - `bitcoin-tx -json` +New mempool information RPC calls +--------------------------------- + +RPC calls have been added to output detailed statistics for individual mempool +entries, as well as to calculate the in-mempool ancestors or descendants of a +transaction: see `getmempoolentry`, `getmempoolancestors`, `getmempooldescendants`. + ### ZMQ Each ZMQ notification now contains an up-counting sequence number that allows diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index f810f89a59..57a576f1c7 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -29,6 +29,7 @@ import subprocess import tempfile import re +sys.path.append("qa/pull-tester/") from tests_config import * BOLD = ("","") @@ -37,7 +38,7 @@ if os.name == 'posix': # terminal via ANSI escape sequences: BOLD = ('\033[0m', '\033[1m') -RPC_TESTS_DIR = BUILDDIR + '/qa/rpc-tests/' +RPC_TESTS_DIR = SRCDIR + '/qa/rpc-tests/' #If imported values are not defined then set to zero (or disabled) if 'ENABLE_WALLET' not in vars(): diff --git a/qa/pull-tester/tests_config.py.in b/qa/pull-tester/tests_config.py.in index 2356b5200e..a0d0a3d98a 100644 --- a/qa/pull-tester/tests_config.py.in +++ b/qa/pull-tester/tests_config.py.in @@ -3,6 +3,7 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. +SRCDIR="@abs_top_srcdir@" BUILDDIR="@abs_top_builddir@" EXEEXT="@EXEEXT@" diff --git a/qa/rpc-tests/bip9-softforks.py b/qa/rpc-tests/bip9-softforks.py index aae258315e..d7e8e5e5a5 100755 --- a/qa/rpc-tests/bip9-softforks.py +++ b/qa/rpc-tests/bip9-softforks.py @@ -80,7 +80,7 @@ class BIP9SoftForksTest(ComparisonTestFramework): info = self.nodes[0].getblockchaininfo() return info['bip9_softforks'][key] - def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignature): + def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignature, bitno): # generate some coins for later self.coinbase_blocks = self.nodes[0].generate(2) self.height = 3 # height of the next block to build @@ -89,6 +89,11 @@ class BIP9SoftForksTest(ComparisonTestFramework): self.last_block_time = int(time.time()) assert_equal(self.get_bip9_status(bipName)['status'], 'defined') + tmpl = self.nodes[0].getblocktemplate({}) + assert(bipName not in tmpl['rules']) + assert(bipName not in tmpl['vbavailable']) + assert_equal(tmpl['vbrequired'], 0) + assert_equal(tmpl['version'], 0x20000000) # Test 1 # Advance from DEFINED to STARTED @@ -96,6 +101,11 @@ class BIP9SoftForksTest(ComparisonTestFramework): yield TestInstance(test_blocks, sync_every_block=False) assert_equal(self.get_bip9_status(bipName)['status'], 'started') + tmpl = self.nodes[0].getblocktemplate({}) + assert(bipName not in tmpl['rules']) + assert_equal(tmpl['vbavailable'][bipName], bitno) + assert_equal(tmpl['vbrequired'], 0) + assert(tmpl['version'] & activated_version) # Test 2 # Fail to achieve LOCKED_IN 100 out of 144 signal bit 1 @@ -107,6 +117,11 @@ class BIP9SoftForksTest(ComparisonTestFramework): yield TestInstance(test_blocks, sync_every_block=False) assert_equal(self.get_bip9_status(bipName)['status'], 'started') + tmpl = self.nodes[0].getblocktemplate({}) + assert(bipName not in tmpl['rules']) + assert_equal(tmpl['vbavailable'][bipName], bitno) + assert_equal(tmpl['vbrequired'], 0) + assert(tmpl['version'] & activated_version) # Test 3 # 108 out of 144 signal bit 1 to achieve LOCKED_IN @@ -118,6 +133,8 @@ class BIP9SoftForksTest(ComparisonTestFramework): yield TestInstance(test_blocks, sync_every_block=False) assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in') + tmpl = self.nodes[0].getblocktemplate({}) + assert(bipName not in tmpl['rules']) # Test 4 # 143 more version 536870913 blocks (waiting period-1) @@ -125,6 +142,8 @@ class BIP9SoftForksTest(ComparisonTestFramework): yield TestInstance(test_blocks, sync_every_block=False) assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in') + tmpl = self.nodes[0].getblocktemplate({}) + assert(bipName not in tmpl['rules']) # Test 5 # Check that the new rule is enforced @@ -148,6 +167,11 @@ class BIP9SoftForksTest(ComparisonTestFramework): yield TestInstance([[block, True]]) assert_equal(self.get_bip9_status(bipName)['status'], 'active') + tmpl = self.nodes[0].getblocktemplate({}) + assert(bipName in tmpl['rules']) + assert(bipName not in tmpl['vbavailable']) + assert_equal(tmpl['vbrequired'], 0) + assert(not (tmpl['version'] & (1 << bitno))) # Test 6 # Check that the new sequence lock rules are enforced @@ -183,9 +207,9 @@ class BIP9SoftForksTest(ComparisonTestFramework): def get_tests(self): for test in itertools.chain( - self.test_BIP('csv', 536870913, self.sequence_lock_invalidate, self.donothing), - self.test_BIP('csv', 536870913, self.mtp_invalidate, self.donothing), - self.test_BIP('csv', 536870913, self.donothing, self.csv_invalidate) + self.test_BIP('csv', 0x20000001, self.sequence_lock_invalidate, self.donothing, 0), + self.test_BIP('csv', 0x20000001, self.mtp_invalidate, self.donothing, 0), + self.test_BIP('csv', 0x20000001, self.donothing, self.csv_invalidate, 0) ): yield test diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py index 5c11d3ab18..998f822afe 100755 --- a/qa/rpc-tests/fundrawtransaction.py +++ b/qa/rpc-tests/fundrawtransaction.py @@ -681,9 +681,9 @@ class RawTransactionsTest(BitcoinTestFramework): inputs = [] outputs = {self.nodes[2].getnewaddress() : 1} rawtx = self.nodes[3].createrawtransaction(inputs, outputs) - result = self.nodes[3].fundrawtransaction(rawtx, ) - result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2000}) - result3 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 10000}) + result = self.nodes[3].fundrawtransaction(rawtx) # uses min_relay_tx_fee (set by settxfee) + result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee}) + result3 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 10*min_relay_tx_fee}) assert_equal(result['fee']*2, result2['fee']) assert_equal(result['fee']*10, result3['fee']) diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py index 693ff593b3..45dc0e65c4 100755 --- a/qa/rpc-tests/mempool_packages.py +++ b/qa/rpc-tests/mempool_packages.py @@ -65,7 +65,14 @@ class MempoolPackagesTest(BitcoinTestFramework): descendant_fees = 0 descendant_size = 0 + descendants = [] + ancestors = list(chain) for x in reversed(chain): + # Check that getmempoolentry is consistent with getrawmempool + entry = self.nodes[0].getmempoolentry(x) + assert_equal(entry, mempool[x]) + + # Check that the descendant calculations are correct assert_equal(mempool[x]['descendantcount'], descendant_count) descendant_fees += mempool[x]['fee'] assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee']) @@ -74,6 +81,27 @@ class MempoolPackagesTest(BitcoinTestFramework): assert_equal(mempool[x]['descendantsize'], descendant_size) descendant_count += 1 + # Check that getmempooldescendants is correct + assert_equal(sorted(descendants), sorted(self.nodes[0].getmempooldescendants(x))) + descendants.append(x) + + # Check that getmempoolancestors is correct + ancestors.remove(x) + assert_equal(sorted(ancestors), sorted(self.nodes[0].getmempoolancestors(x))) + + # Check that getmempoolancestors/getmempooldescendants correctly handle verbose=true + v_ancestors = self.nodes[0].getmempoolancestors(chain[-1], True) + assert_equal(len(v_ancestors), len(chain)-1) + for x in v_ancestors.keys(): + assert_equal(mempool[x], v_ancestors[x]) + assert(chain[-1] not in v_ancestors.keys()) + + v_descendants = self.nodes[0].getmempooldescendants(chain[0], True) + assert_equal(len(v_descendants), len(chain)-1) + for x in v_descendants.keys(): + assert_equal(mempool[x], v_descendants[x]) + assert(chain[0] not in v_descendants.keys()) + # Check that descendant modified fees includes fee deltas from # prioritisetransaction self.nodes[0].prioritisetransaction(chain[-1], 0, 1000) diff --git a/qa/rpc-tests/p2p-mempool.py b/qa/rpc-tests/p2p-mempool.py new file mode 100755 index 0000000000..5d2daf39f8 --- /dev/null +++ b/qa/rpc-tests/p2p-mempool.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.mininode import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import time + +class TestNode(NodeConnCB): + def __init__(self): + NodeConnCB.__init__(self) + self.connection = None + self.ping_counter = 1 + self.last_pong = msg_pong() + self.block_receive_map = {} + + def add_connection(self, conn): + self.connection = conn + self.peer_disconnected = False + + def on_inv(self, conn, message): + pass + + # Track the last getdata message we receive (used in the test) + def on_getdata(self, conn, message): + self.last_getdata = message + + def on_block(self, conn, message): + message.block.calc_sha256() + try: + self.block_receive_map[message.block.sha256] += 1 + except KeyError as e: + self.block_receive_map[message.block.sha256] = 1 + + # Spin until verack message is received from the node. + # We use this to signal that our test can begin. This + # is called from the testing thread, so it needs to acquire + # the global lock. + def wait_for_verack(self): + def veracked(): + return self.verack_received + return wait_until(veracked, timeout=10) + + def wait_for_disconnect(self): + def disconnected(): + return self.peer_disconnected + return wait_until(disconnected, timeout=10) + + # Wrapper for the NodeConn's send_message function + def send_message(self, message): + self.connection.send_message(message) + + def on_pong(self, conn, message): + self.last_pong = message + + def on_close(self, conn): + self.peer_disconnected = True + + # Sync up with the node after delivery of a block + def sync_with_ping(self, timeout=30): + def received_pong(): + return (self.last_pong.nonce == self.ping_counter) + self.connection.send_message(msg_ping(nonce=self.ping_counter)) + success = wait_until(received_pong, timeout) + self.ping_counter += 1 + return success + + def send_mempool(self): + self.lastInv = [] + self.send_message(msg_mempool()) + +class P2PMempoolTests(BitcoinTestFramework): + def setup_chain(self): + initialize_chain_clean(self.options.tmpdir, 2) + + def setup_network(self): + # Start a node with maxuploadtarget of 200 MB (/24h) + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-peerbloomfilters=0"])) + + def run_test(self): + #connect a mininode + aTestNode = TestNode() + node = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], aTestNode) + aTestNode.add_connection(node) + NetworkThread().start() + aTestNode.wait_for_verack() + + #request mempool + aTestNode.send_mempool() + aTestNode.wait_for_disconnect() + + #mininode must be disconnected at this point + assert_equal(len(self.nodes[0].getpeerinfo()), 0) + +if __name__ == '__main__': + P2PMempoolTests().main() diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py index df02c1697f..aa403f058c 100755 --- a/qa/rpc-tests/rawtransactions.py +++ b/qa/rpc-tests/rawtransactions.py @@ -138,5 +138,11 @@ class RawTransactionsTest(BitcoinTestFramework): self.sync_all() assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx + inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}] + outputs = { self.nodes[0].getnewaddress() : 1 } + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + decrawtx= self.nodes[0].decoderawtransaction(rawtx) + assert_equal(decrawtx['vin'][0]['sequence'], 1000) + if __name__ == '__main__': RawTransactionsTest().main() diff --git a/share/genbuild.sh b/share/genbuild.sh index a15cb34e47..1ef77d706f 100755 --- a/share/genbuild.sh +++ b/share/genbuild.sh @@ -15,7 +15,6 @@ fi DESC="" SUFFIX="" -LAST_COMMIT_DATE="" if [ -e "$(which git 2>/dev/null)" -a "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]; then # clean 'dirty' status of touched files that haven't been modified git diff >/dev/null 2>/dev/null @@ -29,9 +28,6 @@ if [ -e "$(which git 2>/dev/null)" -a "$(git rev-parse --is-inside-work-tree 2>/ # otherwise generate suffix from git, i.e. string like "59887e8-dirty" SUFFIX=$(git rev-parse --short HEAD) git diff-index --quiet HEAD -- || SUFFIX="$SUFFIX-dirty" - - # get a string like "2012-04-10 16:27:19 +0200" - LAST_COMMIT_DATE="$(git log -n 1 --format="%ci")" fi if [ -n "$DESC" ]; then @@ -45,7 +41,4 @@ fi # only update build.h if necessary if [ "$INFO" != "$NEWINFO" ]; then echo "$NEWINFO" >"$FILE" - if [ -n "$LAST_COMMIT_DATE" ]; then - echo "#define BUILD_DATE \"$LAST_COMMIT_DATE\"" >> "$FILE" - fi fi diff --git a/src/Makefile.am b/src/Makefile.am index 2f38ecde02..3df8e267bb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -418,8 +418,8 @@ CTAES_DIST += crypto/ctaes/ctaes.h CTAES_DIST += crypto/ctaes/README.md CTAES_DIST += crypto/ctaes/test.c -CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a -CLEANFILES += $(EXTRA_LIBRARIES) +CLEANFILES = $(EXTRA_LIBRARIES) + CLEANFILES += *.gcda *.gcno CLEANFILES += compat/*.gcda compat/*.gcno CLEANFILES += consensus/*.gcda consensus/*.gcno @@ -435,14 +435,14 @@ CLEANFILES += zmq/*.gcda zmq/*.gcno DISTCLEANFILES = obj/build.h -EXTRA_DIST = leveldb $(CTAES_DIST) +EXTRA_DIST = $(CTAES_DIST) clean-local: - -$(MAKE) -C leveldb clean -$(MAKE) -C secp256k1 clean -$(MAKE) -C univalue clean -rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno -rm -f config.h + -rm -rf test/__pycache__ .rc.o: @test -f $(WINDRES) diff --git a/src/Makefile.leveldb.include b/src/Makefile.leveldb.include index 88bb0c1932..4b3cd6364a 100644 --- a/src/Makefile.leveldb.include +++ b/src/Makefile.leveldb.include @@ -26,6 +26,61 @@ leveldb_libleveldb_a_CPPFLAGS = $(AM_CPPFLAGS) $(LEVELDB_CPPFLAGS_INT) $(LEVELDB leveldb_libleveldb_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) leveldb_libleveldb_a_SOURCES= +leveldb_libleveldb_a_SOURCES += leveldb/port/atomic_pointer.h +leveldb_libleveldb_a_SOURCES += leveldb/port/port_example.h +leveldb_libleveldb_a_SOURCES += leveldb/port/port_posix.h +leveldb_libleveldb_a_SOURCES += leveldb/port/win/stdint.h +leveldb_libleveldb_a_SOURCES += leveldb/port/port.h +leveldb_libleveldb_a_SOURCES += leveldb/port/port_win.h +leveldb_libleveldb_a_SOURCES += leveldb/port/thread_annotations.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/db.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/options.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/comparator.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/filter_policy.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/slice.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/table_builder.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/env.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/c.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/iterator.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/cache.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/dumpfile.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/table.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/write_batch.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/status.h +leveldb_libleveldb_a_SOURCES += leveldb/db/log_format.h +leveldb_libleveldb_a_SOURCES += leveldb/db/memtable.h +leveldb_libleveldb_a_SOURCES += leveldb/db/version_set.h +leveldb_libleveldb_a_SOURCES += leveldb/db/write_batch_internal.h +leveldb_libleveldb_a_SOURCES += leveldb/db/filename.h +leveldb_libleveldb_a_SOURCES += leveldb/db/version_edit.h +leveldb_libleveldb_a_SOURCES += leveldb/db/dbformat.h +leveldb_libleveldb_a_SOURCES += leveldb/db/builder.h +leveldb_libleveldb_a_SOURCES += leveldb/db/log_writer.h +leveldb_libleveldb_a_SOURCES += leveldb/db/db_iter.h +leveldb_libleveldb_a_SOURCES += leveldb/db/skiplist.h +leveldb_libleveldb_a_SOURCES += leveldb/db/db_impl.h +leveldb_libleveldb_a_SOURCES += leveldb/db/table_cache.h +leveldb_libleveldb_a_SOURCES += leveldb/db/snapshot.h +leveldb_libleveldb_a_SOURCES += leveldb/db/log_reader.h +leveldb_libleveldb_a_SOURCES += leveldb/table/filter_block.h +leveldb_libleveldb_a_SOURCES += leveldb/table/block_builder.h +leveldb_libleveldb_a_SOURCES += leveldb/table/block.h +leveldb_libleveldb_a_SOURCES += leveldb/table/two_level_iterator.h +leveldb_libleveldb_a_SOURCES += leveldb/table/merger.h +leveldb_libleveldb_a_SOURCES += leveldb/table/format.h +leveldb_libleveldb_a_SOURCES += leveldb/table/iterator_wrapper.h +leveldb_libleveldb_a_SOURCES += leveldb/util/crc32c.h +leveldb_libleveldb_a_SOURCES += leveldb/util/arena.h +leveldb_libleveldb_a_SOURCES += leveldb/util/random.h +leveldb_libleveldb_a_SOURCES += leveldb/util/posix_logger.h +leveldb_libleveldb_a_SOURCES += leveldb/util/hash.h +leveldb_libleveldb_a_SOURCES += leveldb/util/histogram.h +leveldb_libleveldb_a_SOURCES += leveldb/util/coding.h +leveldb_libleveldb_a_SOURCES += leveldb/util/testutil.h +leveldb_libleveldb_a_SOURCES += leveldb/util/mutexlock.h +leveldb_libleveldb_a_SOURCES += leveldb/util/logging.h +leveldb_libleveldb_a_SOURCES += leveldb/util/testharness.h + leveldb_libleveldb_a_SOURCES += leveldb/db/builder.cc leveldb_libleveldb_a_SOURCES += leveldb/db/c.cc leveldb_libleveldb_a_SOURCES += leveldb/db/dbformat.cc @@ -76,3 +131,4 @@ endif leveldb_libmemenv_a_CPPFLAGS = $(leveldb_libleveldb_a_CPPFLAGS) leveldb_libmemenv_a_CXXFLAGS = $(leveldb_libleveldb_a_CXXFLAGS) leveldb_libmemenv_a_SOURCES = leveldb/helpers/memenv/memenv.cc +leveldb_libmemenv_a_SOURCES += leveldb/helpers/memenv/memenv.h diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 3b39919441..9381cca9f2 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -390,19 +390,20 @@ QT_QM=$(QT_TS:.ts=.qm) SECONDARY: $(QT_QM) -qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) +$(srcdir)/qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) @test -n $(XGETTEXT) || echo "xgettext is required for updating translations" $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) PACKAGE_NAME="$(PACKAGE_NAME)" COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" COPYRIGHT_HOLDERS_SUBSTITUTION="$(COPYRIGHT_HOLDERS_SUBSTITUTION)" $(PYTHON) ../share/qt/extract_strings_qt.py $^ -translate: qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) +translate: $(srcdir)/qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) @test -n $(LUPDATE) || echo "lupdate is required for updating translations" - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts qt/locale/bitcoin_en.ts + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts $(srcdir)/qt/locale/bitcoin_en.ts $(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM) @test -f $(RCC) - @test -f $(@D)/$(<F) || cp -f $< $(@D) - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin_locale $(@D)/$(<F) | \ + @cp -f $< $(@D)/temp_$(<F) + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin_locale $(@D)/temp_$(<F) | \ $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@ + @rm $(@D)/temp_$(<F) $(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) $(PROTOBUF_H) @test -f $(RCC) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 77cf1001e1..41d811fb54 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -17,7 +17,9 @@ EXTRA_DIST += \ test/data/txcreate2.hex \ test/data/txcreatedata1.hex \ test/data/txcreatedata2.hex \ - test/data/txcreatesign.hex + test/data/txcreatesign.hex \ + test/data/txcreatedata_seq0.hex \ + test/data/txcreatedata_seq1.hex JSON_TEST_FILES = \ test/data/script_tests.json \ @@ -123,6 +125,9 @@ CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES) CLEANFILES += $(CLEAN_BITCOIN_TEST) +# This file is problematic for out-of-tree builds if it exists. +DISTCLEANFILES += test/buildenv.pyc + bitcoin_test: $(TEST_BINARY) bitcoin_test_check: $(TEST_BINARY) FORCE diff --git a/src/addrman.cpp b/src/addrman.cpp index 6c54cfa4cd..00f6fe99e0 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -197,6 +197,9 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId) void CAddrMan::Good_(const CService& addr, int64_t nTime) { int nId; + + nLastGood = nTime; + CAddrInfo* pinfo = Find(addr, &nId); // if not found, bail out @@ -311,7 +314,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP return fNew; } -void CAddrMan::Attempt_(const CService& addr, int64_t nTime) +void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime) { CAddrInfo* pinfo = Find(addr); @@ -327,7 +330,10 @@ void CAddrMan::Attempt_(const CService& addr, int64_t nTime) // update info info.nLastTry = nTime; - info.nAttempts++; + if (fCountFailure && info.nLastCountAttempt < nLastGood) { + info.nLastCountAttempt = nTime; + info.nAttempts++; + } } CAddrInfo CAddrMan::Select_(bool newOnly) diff --git a/src/addrman.h b/src/addrman.h index 3085450450..c5923e9417 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -29,6 +29,9 @@ public: //! last try whatsoever by us (memory only) int64_t nLastTry; + //! last counted attempt (memory only) + int64_t nLastCountAttempt; + private: //! where knowledge about this address first came from CNetAddr source; @@ -66,6 +69,7 @@ public: { nLastSuccess = 0; nLastTry = 0; + nLastCountAttempt = 0; nAttempts = 0; nRefCount = 0; fInTried = false; @@ -200,6 +204,9 @@ private: //! list of "new" buckets int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]; + //! last time Good was called (memory only) + int64_t nLastGood; + protected: //! secret key to randomize bucket select with uint256 nKey; @@ -230,7 +237,7 @@ protected: bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty); //! Mark an entry as attempted to connect. - void Attempt_(const CService &addr, int64_t nTime); + void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime); //! Select an address to connect to, if newOnly is set to true, only the new table is selected from. CAddrInfo Select_(bool newOnly); @@ -458,6 +465,7 @@ public: nIdCount = 0; nTried = 0; nNew = 0; + nLastGood = 1; //Initially at 1 so that "never" is strictly worse. } CAddrMan() @@ -532,12 +540,12 @@ public: } //! Mark an entry as connection attempted to. - void Attempt(const CService &addr, int64_t nTime = GetAdjustedTime()) + void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime()) { { LOCK(cs); Check(); - Attempt_(addr, nTime); + Attempt_(addr, fCountFailure, nTime); Check(); } } diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 95d7a085a0..f9ea94b9f4 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -71,7 +71,7 @@ static bool AppInitRawTx(int argc, char* argv[]) strUsage = HelpMessageGroup(_("Commands:")); strUsage += HelpMessageOpt("delin=N", _("Delete input N from TX")); strUsage += HelpMessageOpt("delout=N", _("Delete output N from TX")); - strUsage += HelpMessageOpt("in=TXID:VOUT", _("Add input to TX")); + strUsage += HelpMessageOpt("in=TXID:VOUT(:SEQUENCE_NUMBER)", _("Add input to TX")); strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N")); strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N")); strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX")); @@ -181,15 +181,15 @@ static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal) static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput) { + std::vector<std::string> vStrInputParts; + boost::split(vStrInputParts, strInput, boost::is_any_of(":")); + // separate TXID:VOUT in string - size_t pos = strInput.find(':'); - if ((pos == string::npos) || - (pos == 0) || - (pos == (strInput.size() - 1))) + if (vStrInputParts.size()<2) throw runtime_error("TX input missing separator"); // extract and validate TXID - string strTxid = strInput.substr(0, pos); + string strTxid = vStrInputParts[0]; if ((strTxid.size() != 64) || !IsHex(strTxid)) throw runtime_error("invalid TX input txid"); uint256 txid(uint256S(strTxid)); @@ -198,13 +198,18 @@ static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput) static const unsigned int maxVout = MAX_BLOCK_SIZE / minTxOutSz; // extract and validate vout - string strVout = strInput.substr(pos + 1, string::npos); + string strVout = vStrInputParts[1]; int vout = atoi(strVout); if ((vout < 0) || (vout > (int)maxVout)) throw runtime_error("invalid TX input vout"); + // extract the optional sequence number + uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max(); + if (vStrInputParts.size() > 2) + nSequenceIn = std::stoul(vStrInputParts[2]); + // append to transaction input list - CTxIn txin(txid, vout); + CTxIn txin(txid, vout, CScript(), nSequenceIn); tx.vin.push_back(txin); } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 5c7d190125..0005115671 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -16,6 +16,14 @@ #include "chainparamsseeds.h" +std::string CDNSSeedData::getHost(uint64_t requiredServiceBits) const { + //use default host for non-filter-capable seeds or if we use the default service bits (NODE_NETWORK) + if (!supportsServiceBitsFiltering || requiredServiceBits == NODE_NETWORK) + return host; + + return strprintf("x%x.%s", requiredServiceBits, host); +} + static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) { CMutableTransaction txNew; @@ -197,6 +205,8 @@ public: vFixedSeeds.clear(); vSeeds.clear(); + // nodes with support for servicebits filtering should be at the top + vSeeds.push_back(CDNSSeedData("testnetbitcoin.jonasschnelli.ch", "testnet-seed.bitcoin.jonasschnelli.ch", true)); vSeeds.push_back(CDNSSeedData("bitcoin.petertodd.org", "testnet-seed.bitcoin.petertodd.org")); vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me")); vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de")); diff --git a/src/chainparams.h b/src/chainparams.h index 59202f548a..7168daaf43 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -13,9 +13,12 @@ #include <vector> -struct CDNSSeedData { +class CDNSSeedData { +public: std::string name, host; - CDNSSeedData(const std::string &strName, const std::string &strHost) : name(strName), host(strHost) {} + bool supportsServiceBitsFiltering; + std::string getHost(uint64_t requiredServiceBits) const; + CDNSSeedData(const std::string &strName, const std::string &strHost, bool supportsServiceBitsFilteringIn = false) : name(strName), host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {} }; struct SeedSpec6 { diff --git a/src/clientversion.cpp b/src/clientversion.cpp index aae0569bba..bfe9e16f80 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -67,16 +67,7 @@ const std::string CLIENT_NAME("Satoshi"); #endif #endif -#ifndef BUILD_DATE -#ifdef GIT_COMMIT_DATE -#define BUILD_DATE GIT_COMMIT_DATE -#else -#define BUILD_DATE __DATE__ ", " __TIME__ -#endif -#endif - const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX); -const std::string CLIENT_DATE(BUILD_DATE); static std::string FormatVersion(int nVersion) { diff --git a/src/clientversion.h b/src/clientversion.h index 6f255d69c9..47263d5344 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -59,7 +59,6 @@ static const int CLIENT_VERSION = extern const std::string CLIENT_NAME; extern const std::string CLIENT_BUILD; -extern const std::string CLIENT_DATE; std::string FormatFullVersion(); diff --git a/src/coins.cpp b/src/coins.cpp index b7dd293d69..39db7dedfb 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -56,11 +56,7 @@ void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); } -SaltedTxidHasher::SaltedTxidHasher() -{ - GetRandBytes((unsigned char*)&k0, sizeof(k0)); - GetRandBytes((unsigned char*)&k1, sizeof(k1)); -} +SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {} CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), cachedCoinsUsage(0) { } diff --git a/src/coins.h b/src/coins.h index 1dd908700b..033651a435 100644 --- a/src/coins.h +++ b/src/coins.h @@ -269,7 +269,7 @@ class SaltedTxidHasher { private: /** Salt */ - uint64_t k0, k1; + const uint64_t k0, k1; public: SaltedTxidHasher(); diff --git a/src/consensus/params.h b/src/consensus/params.h index 4f3480b89b..6c4cc49479 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -16,6 +16,7 @@ enum DeploymentPos { DEPLOYMENT_TESTDUMMY, DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113. + // NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp MAX_VERSION_BITS_DEPLOYMENTS }; diff --git a/src/hash.cpp b/src/hash.cpp index a518314a53..20a83342db 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -100,12 +100,15 @@ CSipHasher::CSipHasher(uint64_t k0, uint64_t k1) v[2] = 0x6c7967656e657261ULL ^ k0; v[3] = 0x7465646279746573ULL ^ k1; count = 0; + tmp = 0; } CSipHasher& CSipHasher::Write(uint64_t data) { uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; + assert(count % 8 == 0); + v3 ^= data; SIPROUND; SIPROUND; @@ -116,7 +119,35 @@ CSipHasher& CSipHasher::Write(uint64_t data) v[2] = v2; v[3] = v3; - count++; + count += 8; + return *this; +} + +CSipHasher& CSipHasher::Write(const unsigned char* data, size_t size) +{ + uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; + uint64_t t = tmp; + int c = count; + + while (size--) { + t |= ((uint64_t)(*(data++))) << (8 * (c % 8)); + c++; + if ((c & 7) == 0) { + v3 ^= t; + SIPROUND; + SIPROUND; + v0 ^= t; + t = 0; + } + } + + v[0] = v0; + v[1] = v1; + v[2] = v2; + v[3] = v3; + count = c; + tmp = t; + return *this; } @@ -124,10 +155,12 @@ uint64_t CSipHasher::Finalize() const { uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; - v3 ^= ((uint64_t)count) << 59; + uint64_t t = tmp | (((uint64_t)count) << 56); + + v3 ^= t; SIPROUND; SIPROUND; - v0 ^= ((uint64_t)count) << 59; + v0 ^= t; v2 ^= 0xFF; SIPROUND; SIPROUND; diff --git a/src/hash.h b/src/hash.h index 600dabec56..db4e130ae7 100644 --- a/src/hash.h +++ b/src/hash.h @@ -171,19 +171,38 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]); -/** SipHash-2-4, using a uint64_t-based (rather than byte-based) interface */ +/** SipHash-2-4 */ class CSipHasher { private: uint64_t v[4]; + uint64_t tmp; int count; public: + /** Construct a SipHash calculator initialized with 128-bit key (k0, k1) */ CSipHasher(uint64_t k0, uint64_t k1); + /** Hash a 64-bit integer worth of data + * It is treated as if this was the little-endian interpretation of 8 bytes. + * This function can only be used when a multiple of 8 bytes have been written so far. + */ CSipHasher& Write(uint64_t data); + /** Hash arbitrary bytes. */ + CSipHasher& Write(const unsigned char* data, size_t size); + /** Compute the 64-bit SipHash-2-4 of the data written so far. The object remains untouched. */ uint64_t Finalize() const; }; +/** Optimized SipHash-2-4 implementation for uint256. + * + * It is identical to: + * SipHasher(k0, k1) + * .Write(val.GetUint64(0)) + * .Write(val.GetUint64(1)) + * .Write(val.GetUint64(2)) + * .Write(val.GetUint64(3)) + * .Finalize() + */ uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val); #endif // BITCOIN_HASH_H diff --git a/src/init.cpp b/src/init.cpp index 9a22501859..ec4ce6b6da 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -319,7 +319,8 @@ std::string HelpMessage(HelpMessageMode mode) } strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory")); strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache)); - strUsage += HelpMessageOpt("-feefilter", strprintf(_("Tell other nodes to filter invs to us by our mempool min fee (default: %u)"), DEFAULT_FEEFILTER)); + if (showDebug) + strUsage += HelpMessageOpt("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER)); strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file on startup")); strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS)); strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE)); @@ -747,7 +748,7 @@ void InitLogging() fLogIPs = GetBoolArg("-logips", DEFAULT_LOGIPS); LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - LogPrintf("Bitcoin version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); + LogPrintf("Bitcoin version %s\n", FormatFullVersion()); } /** Initialize bitcoin. diff --git a/src/main.cpp b/src/main.cpp index fc8e72a7db..6d006e8789 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -81,9 +81,6 @@ uint64_t nPruneTarget = 0; int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; -std::map<uint256, CTransaction> mapRelay; -std::deque<std::pair<int64_t, uint256> > vRelayExpiration; -CCriticalSection cs_mapRelay; CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; @@ -216,6 +213,12 @@ namespace { /** Number of peers from which we're downloading blocks. */ int nPeersWithValidatedDownloads = 0; + + /** Relay map, protected by cs_main. */ + typedef std::map<uint256, std::shared_ptr<const CTransaction>> MapRelay; + MapRelay mapRelay; + /** Expiration-time ordered list of (expire time, relay map entry) pairs, protected by cs_main). */ + std::deque<std::pair<int64_t, MapRelay::iterator>> vRelayExpiration; } // anon namespace ////////////////////////////////////////////////////////////////////////////// @@ -1443,8 +1446,10 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P LOCK(cs_main); - if (mempool.lookup(hash, txOut)) + std::shared_ptr<const CTransaction> ptx = mempool.get(hash); + if (ptx) { + txOut = *ptx; return true; } @@ -2176,7 +2181,7 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const } // Protected by cs_main -static VersionBitsCache versionbitscache; +VersionBitsCache versionbitscache; int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) { @@ -3883,10 +3888,18 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, CBlockIndex* pindexFailure = NULL; int nGoodTransactions = 0; CValidationState state; + int reportDone = 0; + LogPrintf("[0%]..."); for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { boost::this_thread::interruption_point(); - uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))))); + int percentageDone = std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); + if (reportDone < percentageDone/10) { + // report every 10% step + LogPrintf("[%d%%]...", percentageDone); + reportDone = percentageDone/10; + } + uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone); if (pindex->nHeight < chainActive.Height()-nCheckDepth) break; if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) { @@ -3944,6 +3957,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, } } + LogPrintf("[DONE].\n"); LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->nHeight, nGoodTransactions); return true; @@ -4512,30 +4526,24 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } } } - else if (inv.IsKnownType()) + else if (inv.type == MSG_TX) { - CTransaction tx; // Send stream from relay memory bool push = false; - { - LOCK(cs_mapRelay); - map<uint256, CTransaction>::iterator mi = mapRelay.find(inv.hash); - if (mi != mapRelay.end()) { - tx = (*mi).second; - push = true; - } - } - if (!push && inv.type == MSG_TX) { - int64_t txtime; + auto mi = mapRelay.find(inv.hash); + if (mi != mapRelay.end()) { + pfrom->PushMessage(NetMsgType::TX, *mi->second); + push = true; + } else if (pfrom->timeLastMempoolReq) { + auto txinfo = mempool.info(inv.hash); // To protect privacy, do not answer getdata using the mempool when // that TX couldn't have been INVed in reply to a MEMPOOL request. - if (mempool.lookup(inv.hash, tx, txtime) && txtime <= pfrom->timeLastMempoolReq) { + if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) { + pfrom->PushMessage(NetMsgType::TX, *txinfo.tx); push = true; } } - if (push) { - pfrom->PushMessage(inv.GetCommand(), tx); - } else { + if (!push) { vNotFound.push_back(inv); } } @@ -4775,11 +4783,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LOCK(cs_vNodes); // Use deterministic randomness to send to the same nodes for 24 hours // at a time so the addrKnowns of the chosen nodes prevent repeats - static uint64_t salt0 = 0, salt1 = 0; - while (salt0 == 0 && salt1 == 0) { - GetRandBytes((unsigned char*)&salt0, sizeof(salt0)); - GetRandBytes((unsigned char*)&salt1, sizeof(salt1)); - } + static const uint64_t salt0 = GetRand(std::numeric_limits<uint64_t>::max()); + static const uint64_t salt1 = GetRand(std::numeric_limits<uint64_t>::max()); uint64_t hashAddr = addr.GetHash(); multimap<uint64_t, CNode*> mapMix; const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60)); @@ -5310,6 +5315,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == NetMsgType::MEMPOOL) { + if (!(nLocalServices & NODE_BLOOM) && !pfrom->fWhitelisted) + { + LogPrint("net", "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId()); + pfrom->fDisconnect = true; + return true; + } + if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted) { LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId()); @@ -5713,6 +5725,9 @@ bool SendMessages(CNode* pto) pto->vAddrToSend.clear(); if (!vAddr.empty()) pto->PushMessage(NetMsgType::ADDR, vAddr); + // we only send the big addr message once + if (pto->vAddrToSend.capacity() > 40) + pto->vAddrToSend.shrink_to_fit(); } CNodeState &state = *State(pto->GetId()); @@ -5907,8 +5922,7 @@ bool SendMessages(CNode* pto) // Respond to BIP35 mempool requests if (fSendTrickle && pto->fSendMempool) { - std::vector<uint256> vtxid; - mempool.queryHashes(vtxid); + auto vtxinfo = mempool.infoAll(); pto->fSendMempool = false; CAmount filterrate = 0; { @@ -5918,20 +5932,16 @@ bool SendMessages(CNode* pto) LOCK(pto->cs_filter); - BOOST_FOREACH(const uint256& hash, vtxid) { + for (const auto& txinfo : vtxinfo) { + const uint256& hash = txinfo.tx->GetHash(); CInv inv(MSG_TX, hash); pto->setInventoryTxToSend.erase(hash); if (filterrate) { - CFeeRate feeRate; - mempool.lookupFeeRate(hash, feeRate); - if (feeRate.GetFeePerK() < filterrate) + if (txinfo.feeRate.GetFeePerK() < filterrate) continue; } if (pto->pfilter) { - CTransaction tx; - bool fInMemPool = mempool.lookup(hash, tx); - if (!fInMemPool) continue; // another thread removed since queryHashes, maybe... - if (!pto->pfilter->IsRelevantAndUpdate(tx)) continue; + if (!pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue; } pto->filterInventoryKnown.insert(hash); vInv.push_back(inv); @@ -5977,31 +5987,28 @@ bool SendMessages(CNode* pto) continue; } // Not in the mempool anymore? don't bother sending it. - CFeeRate feeRate; - if (!mempool.lookupFeeRate(hash, feeRate)) { + auto txinfo = mempool.info(hash); + if (!txinfo.tx) { continue; } - if (filterrate && feeRate.GetFeePerK() < filterrate) { + if (filterrate && txinfo.feeRate.GetFeePerK() < filterrate) { continue; } - CTransaction tx; - if (!mempool.lookup(hash, tx)) continue; - if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(tx)) continue; + if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue; // Send vInv.push_back(CInv(MSG_TX, hash)); nRelayedTransactions++; { - LOCK(cs_mapRelay); // Expire old relay messages - while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime()) + while (!vRelayExpiration.empty() && vRelayExpiration.front().first < nNow) { mapRelay.erase(vRelayExpiration.front().second); vRelayExpiration.pop_front(); } - auto ret = mapRelay.insert(std::make_pair(hash, tx)); + auto ret = mapRelay.insert(std::make_pair(hash, std::move(txinfo.tx))); if (ret.second) { - vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, hash)); + vRelayExpiration.push_back(std::make_pair(nNow + 15 * 60 * 1000000, ret.first)); } } if (vInv.size() == MAX_INV_SZ) { diff --git a/src/main.h b/src/main.h index 4e93c084f4..9b99ae7c87 100644 --- a/src/main.h +++ b/src/main.h @@ -482,6 +482,8 @@ extern CBlockTreeDB *pblocktree; */ int GetSpendHeight(const CCoinsViewCache& inputs); +extern VersionBitsCache versionbitscache; + /** * Determine what nVersion a new block should use. */ diff --git a/src/memusage.h b/src/memusage.h index 9c98e5c2cf..3810bfad07 100644 --- a/src/memusage.h +++ b/src/memusage.h @@ -72,6 +72,15 @@ private: X x; }; +struct stl_shared_counter +{ + /* Various platforms use different sized counters here. + * Conservatively assume that they won't be larger than size_t. */ + void* class_type; + size_t use_count; + size_t weak_count; +}; + template<typename X> static inline size_t DynamicUsage(const std::vector<X>& v) { @@ -122,6 +131,21 @@ static inline size_t IncrementalDynamicUsage(const indirectmap<X, Y>& m) return MallocUsage(sizeof(stl_tree_node<std::pair<const X*, Y> >)); } +template<typename X> +static inline size_t DynamicUsage(const std::unique_ptr<X>& p) +{ + return p ? MallocUsage(sizeof(X)) : 0; +} + +template<typename X> +static inline size_t DynamicUsage(const std::shared_ptr<X>& p) +{ + // A shared_ptr can either use a single continuous memory block for both + // the counter and the storage (when using std::make_shared), or separate. + // We can't observe the difference, however, so assume the worst. + return p ? MallocUsage(sizeof(X)) + MallocUsage(sizeof(stl_shared_counter)) : 0; +} + // Boost data structures template<typename X> diff --git a/src/net.cpp b/src/net.cpp index c09e3aedb6..173eba57c8 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -14,6 +14,7 @@ #include "clientversion.h" #include "consensus/consensus.h" #include "crypto/common.h" +#include "crypto/sha256.h" #include "hash.h" #include "primitives/transaction.h" #include "scheduler.h" @@ -365,7 +366,7 @@ CNode* FindNode(const CService& addr) return NULL; } -CNode* ConnectNode(CAddress addrConnect, const char *pszDest) +CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) { if (pszDest == NULL) { if (IsLocal(addrConnect)) @@ -397,7 +398,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) return NULL; } - addrman.Attempt(addrConnect); + addrman.Attempt(addrConnect, fCountFailure); // Add node CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); @@ -414,7 +415,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) } else if (!proxyConnectionFailed) { // If connecting to the node failed, and failure is not caused by a problem connecting to // the proxy, mark this as an attempt. - addrman.Attempt(addrConnect); + addrman.Attempt(addrConnect, fCountFailure); } return NULL; @@ -838,6 +839,7 @@ struct NodeEvictionCandidate int64_t nTimeConnected; int64_t nMinPingUsecTime; CAddress addr; + uint64_t nKeyedNetGroup; }; static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) @@ -850,36 +852,8 @@ static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, cons return a.nTimeConnected > b.nTimeConnected; } -class CompareNetGroupKeyed -{ - std::vector<unsigned char> vchSecretKey; -public: - CompareNetGroupKeyed() - { - vchSecretKey.resize(32, 0); - GetRandBytes(vchSecretKey.data(), vchSecretKey.size()); - } - - bool operator()(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) - { - std::vector<unsigned char> vchGroupA, vchGroupB; - CSHA256 hashA, hashB; - std::vector<unsigned char> vchA(32), vchB(32); - - vchGroupA = a.addr.GetGroup(); - vchGroupB = b.addr.GetGroup(); - - hashA.Write(begin_ptr(vchGroupA), vchGroupA.size()); - hashB.Write(begin_ptr(vchGroupB), vchGroupB.size()); - - hashA.Write(begin_ptr(vchSecretKey), vchSecretKey.size()); - hashB.Write(begin_ptr(vchSecretKey), vchSecretKey.size()); - - hashA.Finalize(begin_ptr(vchA)); - hashB.Finalize(begin_ptr(vchB)); - - return vchA < vchB; - } +static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) { + return a.nKeyedNetGroup < b.nKeyedNetGroup; }; /** Try to find a connection to evict when the node is full. @@ -902,7 +876,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { continue; if (node->fDisconnect) continue; - NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr}; + NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr, node->nKeyedNetGroup}; vEvictionCandidates.push_back(candidate); } } @@ -912,9 +886,8 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { // Protect connections with certain characteristics // Deterministically select 4 peers to protect by netgroup. - // An attacker cannot predict which netgroups will be protected. - static CompareNetGroupKeyed comparerNetGroupKeyed; - std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), comparerNetGroupKeyed); + // An attacker cannot predict which netgroups will be protected + std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNetGroupKeyed); vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end()); if (vEvictionCandidates.empty()) return false; @@ -935,24 +908,24 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { // Identify the network group with the most connections and youngest member. // (vEvictionCandidates is already sorted by reverse connect time) - std::vector<unsigned char> naMostConnections; + uint64_t naMostConnections; unsigned int nMostConnections = 0; int64_t nMostConnectionsTime = 0; - std::map<std::vector<unsigned char>, std::vector<NodeEvictionCandidate> > mapAddrCounts; + std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapAddrCounts; BOOST_FOREACH(const NodeEvictionCandidate &node, vEvictionCandidates) { - mapAddrCounts[node.addr.GetGroup()].push_back(node); - int64_t grouptime = mapAddrCounts[node.addr.GetGroup()][0].nTimeConnected; - size_t groupsize = mapAddrCounts[node.addr.GetGroup()].size(); + mapAddrCounts[node.nKeyedNetGroup].push_back(node); + int64_t grouptime = mapAddrCounts[node.nKeyedNetGroup][0].nTimeConnected; + size_t groupsize = mapAddrCounts[node.nKeyedNetGroup].size(); if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) { nMostConnections = groupsize; nMostConnectionsTime = grouptime; - naMostConnections = node.addr.GetGroup(); + naMostConnections = node.nKeyedNetGroup; } } // Reduce to the network group with the most connections - vEvictionCandidates = mapAddrCounts[naMostConnections]; + vEvictionCandidates = std::move(mapAddrCounts[naMostConnections]); // Do not disconnect peers if there is only one unprotected connection from their network group. // This step excessively favors netgroup diversity, and should be removed once more protective criteria are established. @@ -1464,12 +1437,13 @@ void ThreadDNSAddressSeed() } else { std::vector<CNetAddr> vIPs; std::vector<CAddress> vAdd; - if (LookupHost(seed.host.c_str(), vIPs, 0, true)) + uint64_t requiredServiceBits = NODE_NETWORK; + if (LookupHost(seed.getHost(requiredServiceBits).c_str(), vIPs, 0, true)) { BOOST_FOREACH(const CNetAddr& ip, vIPs) { int nOneDay = 24*3600; - CAddress addr = CAddress(CService(ip, Params().GetDefaultPort())); + CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits); addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old vAdd.push_back(addr); found++; @@ -1531,7 +1505,7 @@ void static ProcessOneShot() CAddress addr; CSemaphoreGrant grant(*semOutbound, true); if (grant) { - if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true)) + if (!OpenNetworkConnection(addr, false, &grant, strDest.c_str(), true)) AddOneShot(strDest); } } @@ -1547,7 +1521,7 @@ void ThreadOpenConnections() BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"]) { CAddress addr; - OpenNetworkConnection(addr, NULL, strAddr.c_str()); + OpenNetworkConnection(addr, false, NULL, strAddr.c_str()); for (int i = 0; i < 10 && i < nLoop; i++) { MilliSleep(500); @@ -1631,7 +1605,7 @@ void ThreadOpenConnections() } if (addrConnect.IsValid()) - OpenNetworkConnection(addrConnect, &grant); + OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant); } } @@ -1653,7 +1627,7 @@ void ThreadOpenAddedConnections() BOOST_FOREACH(const std::string& strAddNode, lAddresses) { CAddress addr; CSemaphoreGrant grant(*semOutbound); - OpenNetworkConnection(addr, &grant, strAddNode.c_str()); + OpenNetworkConnection(addr, false, &grant, strAddNode.c_str()); MilliSleep(500); } MilliSleep(120000); // Retry every 2 minutes @@ -1692,7 +1666,7 @@ void ThreadOpenAddedConnections() BOOST_FOREACH(std::vector<CService>& vserv, lservAddressesToAdd) { CSemaphoreGrant grant(*semOutbound); - OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant); + OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), false, &grant); MilliSleep(500); } MilliSleep(120000); // Retry every 2 minutes @@ -1700,7 +1674,7 @@ void ThreadOpenAddedConnections() } // if successful, this moves the passed grant to the constructed node -bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot) +bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot) { // // Initiate outbound network connection @@ -1714,7 +1688,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu } else if (FindNode(std::string(pszDest))) return false; - CNode* pnode = ConnectNode(addrConnect, pszDest); + CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure); boost::this_thread::interruption_point(); if (!pnode) @@ -2345,6 +2319,8 @@ unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAX CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), + addr(addrIn), + nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), addrKnown(5000, 0.001), filterInventoryKnown(50000, 0.000001) { @@ -2357,7 +2333,6 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nRecvBytes = 0; nTimeConnected = GetTime(); nTimeOffset = 0; - addr = addrIn; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; nVersion = 0; strSubVer = ""; @@ -2624,3 +2599,13 @@ bool CBanDB::Read(banmap_t& banSet) int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } + +/* static */ uint64_t CNode::CalculateKeyedNetGroup(const CAddress& ad) +{ + static const uint64_t k0 = GetRand(std::numeric_limits<uint64_t>::max()); + static const uint64_t k1 = GetRand(std::numeric_limits<uint64_t>::max()); + + std::vector<unsigned char> vchNetGroup(ad.GetGroup()); + + return CSipHasher(k0, k1).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize(); +} @@ -84,7 +84,7 @@ CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CSubNet& subNet); CNode* FindNode(const std::string& addrName); CNode* FindNode(const CService& ip); -bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false); +bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false); void MapPort(bool fUseUPnP); unsigned short GetListenPort(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); @@ -335,7 +335,7 @@ public: int64_t nLastRecv; int64_t nTimeConnected; int64_t nTimeOffset; - CAddress addr; + const CAddress addr; std::string addrName; CService addrLocal; int nVersion; @@ -362,6 +362,8 @@ public: CBloomFilter* pfilter; int nRefCount; NodeId id; + + const uint64_t nKeyedNetGroup; protected: // Denial-of-service detection/prevention @@ -450,6 +452,8 @@ private: CNode(const CNode&); void operator=(const CNode&); + static uint64_t CalculateKeyedNetGroup(const CAddress& ad); + public: NodeId GetId() const { diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 23be8e016b..9e53f19591 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -140,8 +140,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" QT_TRANSLATE_NOOP("bitcoin-core", "" "Support filtering of blocks and transaction with bloom filters (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Tell other nodes to filter invs to us by our mempool min fee (default: %u)"), -QT_TRANSLATE_NOOP("bitcoin-core", "" "The block database contains a block which appears to be from the future. " "This may be due to your computer's date and time being set incorrectly. Only " "rebuild the block database if you are sure that your computer's date and " diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 5549ccd4f8..b90221f2c2 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -3785,7 +3785,7 @@ <context> <name>bitcoin-core</name> <message> - <location filename="../bitcoinstrings.cpp" line="+288"/> + <location filename="../bitcoinstrings.cpp" line="+286"/> <source>Options:</source> <translation>Options:</translation> </message> @@ -3810,7 +3810,7 @@ <translation>Accept command line and JSON-RPC commands</translation> </message> <message> - <location line="-127"/> + <location line="-125"/> <source>If <category> is not supplied or if <category> = 1, output all debugging information.</source> <translation type="unfinished"></translation> </message> @@ -3835,7 +3835,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+120"/> + <location line="+118"/> <source>Error: A fatal internal error occurred, see debug.log for details</source> <translation type="unfinished"></translation> </message> @@ -3865,7 +3865,7 @@ <translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation> </message> <message> - <location line="-203"/> + <location line="-201"/> <source>Bitcoin Core</source> <translation type="unfinished">Bitcoin Core</translation> </message> @@ -3946,11 +3946,6 @@ </message> <message> <location line="+5"/> - <source>Tell other nodes to filter invs to us by our mempool min fee (default: %u)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+2"/> <source>The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source> <translation type="unfinished"></translation> </message> @@ -4305,7 +4300,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-315"/> + <location line="-313"/> <source>Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times</source> <translation type="unfinished"></translation> </message> @@ -4375,7 +4370,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+12"/> <source>The transaction amount is too small to send after the fee has been deducted</source> <translation type="unfinished"></translation> </message> @@ -4580,12 +4575,12 @@ <translation>Password for JSON-RPC connections</translation> </message> <message> - <location line="-216"/> + <location line="-214"/> <source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source> <translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation> </message> <message> - <location line="+145"/> + <location line="+143"/> <source>Allow DNS lookups for -addnode, -seednode and -connect</source> <translation>Allow DNS lookups for -addnode, -seednode and -connect</translation> </message> @@ -4595,7 +4590,7 @@ <translation>Loading addresses...</translation> </message> <message> - <location line="-260"/> + <location line="-258"/> <source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source> <translation type="unfinished"></translation> </message> @@ -4645,7 +4640,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+18"/> + <location line="+16"/> <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> <translation type="unfinished"></translation> </message> diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index cf3c73c4df..1bb365d36c 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -183,6 +183,60 @@ UniValue getdifficulty(const UniValue& params, bool fHelp) return GetDifficulty(); } +std::string EntryDescriptionString() +{ + return " \"size\" : n, (numeric) transaction size in bytes\n" + " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n" + " \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n" + " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n" + " \"height\" : n, (numeric) block height when transaction entered pool\n" + " \"startingpriority\" : n, (numeric) priority when transaction entered pool\n" + " \"currentpriority\" : n, (numeric) transaction priority now\n" + " \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n" + " \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n" + " \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n" + " \"ancestorcount\" : n, (numeric) number of in-mempool ancestor transactions (including this one)\n" + " \"ancestorsize\" : n, (numeric) size of in-mempool ancestors (including this one)\n" + " \"ancestorfees\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one)\n" + " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n" + " \"transactionid\", (string) parent transaction id\n" + " ... ]\n"; +} + +void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) +{ + AssertLockHeld(mempool.cs); + + info.push_back(Pair("size", (int)e.GetTxSize())); + info.push_back(Pair("fee", ValueFromAmount(e.GetFee()))); + info.push_back(Pair("modifiedfee", ValueFromAmount(e.GetModifiedFee()))); + info.push_back(Pair("time", e.GetTime())); + info.push_back(Pair("height", (int)e.GetHeight())); + info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight()))); + info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height()))); + info.push_back(Pair("descendantcount", e.GetCountWithDescendants())); + info.push_back(Pair("descendantsize", e.GetSizeWithDescendants())); + info.push_back(Pair("descendantfees", e.GetModFeesWithDescendants())); + info.push_back(Pair("ancestorcount", e.GetCountWithAncestors())); + info.push_back(Pair("ancestorsize", e.GetSizeWithAncestors())); + info.push_back(Pair("ancestorfees", e.GetModFeesWithAncestors())); + const CTransaction& tx = e.GetTx(); + set<string> setDepends; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + if (mempool.exists(txin.prevout.hash)) + setDepends.insert(txin.prevout.hash.ToString()); + } + + UniValue depends(UniValue::VARR); + BOOST_FOREACH(const string& dep, setDepends) + { + depends.push_back(dep); + } + + info.push_back(Pair("depends", depends)); +} + UniValue mempoolToJSON(bool fVerbose = false) { if (fVerbose) @@ -193,31 +247,7 @@ UniValue mempoolToJSON(bool fVerbose = false) { const uint256& hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); - info.push_back(Pair("size", (int)e.GetTxSize())); - info.push_back(Pair("fee", ValueFromAmount(e.GetFee()))); - info.push_back(Pair("modifiedfee", ValueFromAmount(e.GetModifiedFee()))); - info.push_back(Pair("time", e.GetTime())); - info.push_back(Pair("height", (int)e.GetHeight())); - info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight()))); - info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height()))); - info.push_back(Pair("descendantcount", e.GetCountWithDescendants())); - info.push_back(Pair("descendantsize", e.GetSizeWithDescendants())); - info.push_back(Pair("descendantfees", e.GetModFeesWithDescendants())); - const CTransaction& tx = e.GetTx(); - set<string> setDepends; - BOOST_FOREACH(const CTxIn& txin, tx.vin) - { - if (mempool.exists(txin.prevout.hash)) - setDepends.insert(txin.prevout.hash.ToString()); - } - - UniValue depends(UniValue::VARR); - BOOST_FOREACH(const string& dep, setDepends) - { - depends.push_back(dep); - } - - info.push_back(Pair("depends", depends)); + entryToJSON(info, e); o.push_back(Pair(hash.ToString(), info)); } return o; @@ -251,20 +281,8 @@ UniValue getrawmempool(const UniValue& params, bool fHelp) "\nResult: (for verbose = true):\n" "{ (json object)\n" " \"transactionid\" : { (json object)\n" - " \"size\" : n, (numeric) transaction size in bytes\n" - " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n" - " \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n" - " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n" - " \"height\" : n, (numeric) block height when transaction entered pool\n" - " \"startingpriority\" : n, (numeric) priority when transaction entered pool\n" - " \"currentpriority\" : n, (numeric) transaction priority now\n" - " \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n" - " \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n" - " \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n" - " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n" - " \"transactionid\", (string) parent transaction id\n" - " ... ]\n" - " }, ...\n" + + EntryDescriptionString() + + " }, ...\n" "}\n" "\nExamples\n" + HelpExampleCli("getrawmempool", "true") @@ -280,6 +298,167 @@ UniValue getrawmempool(const UniValue& params, bool fHelp) return mempoolToJSON(fVerbose); } +UniValue getmempoolancestors(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) { + throw runtime_error( + "getmempoolancestors txid (verbose)\n" + "\nIf txid is in the mempool, returns all in-mempool ancestors.\n" + "\nArguments:\n" + "1. \"txid\" (string, required) The transaction id (must be in mempool)\n" + "2. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n" + "\nResult (for verbose=false):\n" + "[ (json array of strings)\n" + " \"transactionid\" (string) The transaction id of an in-mempool ancestor transaction\n" + " ,...\n" + "]\n" + "\nResult (for verbose=true):\n" + "{ (json object)\n" + " \"transactionid\" : { (json object)\n" + + EntryDescriptionString() + + " }, ...\n" + "}\n" + "\nExamples\n" + + HelpExampleCli("getmempoolancestors", "\"mytxid\"") + + HelpExampleRpc("getmempoolancestors", "\"mytxid\"") + ); + } + + bool fVerbose = false; + if (params.size() > 1) + fVerbose = params[1].get_bool(); + + uint256 hash = ParseHashV(params[0], "parameter 1"); + + LOCK(mempool.cs); + + CTxMemPool::txiter it = mempool.mapTx.find(hash); + if (it == mempool.mapTx.end()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool"); + } + + CTxMemPool::setEntries setAncestors; + uint64_t noLimit = std::numeric_limits<uint64_t>::max(); + std::string dummy; + mempool.CalculateMemPoolAncestors(*it, setAncestors, noLimit, noLimit, noLimit, noLimit, dummy, false); + + if (!fVerbose) { + UniValue o(UniValue::VARR); + BOOST_FOREACH(CTxMemPool::txiter ancestorIt, setAncestors) { + o.push_back(ancestorIt->GetTx().GetHash().ToString()); + } + + return o; + } else { + UniValue o(UniValue::VOBJ); + BOOST_FOREACH(CTxMemPool::txiter ancestorIt, setAncestors) { + const CTxMemPoolEntry &e = *ancestorIt; + const uint256& hash = e.GetTx().GetHash(); + UniValue info(UniValue::VOBJ); + entryToJSON(info, e); + o.push_back(Pair(hash.ToString(), info)); + } + return o; + } +} + +UniValue getmempooldescendants(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) { + throw runtime_error( + "getmempooldescendants txid (verbose)\n" + "\nIf txid is in the mempool, returns all in-mempool descendants.\n" + "\nArguments:\n" + "1. \"txid\" (string, required) The transaction id (must be in mempool)\n" + "2. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n" + "\nResult (for verbose=false):\n" + "[ (json array of strings)\n" + " \"transactionid\" (string) The transaction id of an in-mempool descendant transaction\n" + " ,...\n" + "]\n" + "\nResult (for verbose=true):\n" + "{ (json object)\n" + " \"transactionid\" : { (json object)\n" + + EntryDescriptionString() + + " }, ...\n" + "}\n" + "\nExamples\n" + + HelpExampleCli("getmempooldescendants", "\"mytxid\"") + + HelpExampleRpc("getmempooldescendants", "\"mytxid\"") + ); + } + + bool fVerbose = false; + if (params.size() > 1) + fVerbose = params[1].get_bool(); + + uint256 hash = ParseHashV(params[0], "parameter 1"); + + LOCK(mempool.cs); + + CTxMemPool::txiter it = mempool.mapTx.find(hash); + if (it == mempool.mapTx.end()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool"); + } + + CTxMemPool::setEntries setDescendants; + mempool.CalculateDescendants(it, setDescendants); + // CTxMemPool::CalculateDescendants will include the given tx + setDescendants.erase(it); + + if (!fVerbose) { + UniValue o(UniValue::VARR); + BOOST_FOREACH(CTxMemPool::txiter descendantIt, setDescendants) { + o.push_back(descendantIt->GetTx().GetHash().ToString()); + } + + return o; + } else { + UniValue o(UniValue::VOBJ); + BOOST_FOREACH(CTxMemPool::txiter descendantIt, setDescendants) { + const CTxMemPoolEntry &e = *descendantIt; + const uint256& hash = e.GetTx().GetHash(); + UniValue info(UniValue::VOBJ); + entryToJSON(info, e); + o.push_back(Pair(hash.ToString(), info)); + } + return o; + } +} + +UniValue getmempoolentry(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) { + throw runtime_error( + "getmempoolentry txid\n" + "\nReturns mempool data for given transaction\n" + "\nArguments:\n" + "1. \"txid\" (string, required) The transaction id (must be in mempool)\n" + "\nResult:\n" + "{ (json object)\n" + + EntryDescriptionString() + + "}\n" + "\nExamples\n" + + HelpExampleCli("getmempoolentry", "\"mytxid\"") + + HelpExampleRpc("getmempoolentry", "\"mytxid\"") + ); + } + + uint256 hash = ParseHashV(params[0], "parameter 1"); + + LOCK(mempool.cs); + + CTxMemPool::txiter it = mempool.mapTx.find(hash); + if (it == mempool.mapTx.end()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool"); + } + + const CTxMemPoolEntry &e = *it; + UniValue info(UniValue::VOBJ); + entryToJSON(info, e); + return info; +} + UniValue getblockhash(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) @@ -1004,6 +1183,9 @@ static const CRPCCommand commands[] = { "blockchain", "getblockheader", &getblockheader, true }, { "blockchain", "getchaintips", &getchaintips, true }, { "blockchain", "getdifficulty", &getdifficulty, true }, + { "blockchain", "getmempoolancestors", &getmempoolancestors, true }, + { "blockchain", "getmempooldescendants", &getmempooldescendants, true }, + { "blockchain", "getmempoolentry", &getmempoolentry, true }, { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, { "blockchain", "getrawmempool", &getrawmempool, true }, { "blockchain", "gettxout", &gettxout, true }, diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index c89af6bfa7..d0675fdb49 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -102,6 +102,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "prioritisetransaction", 2 }, { "setban", 2 }, { "setban", 3 }, + { "getmempoolancestors", 1 }, + { "getmempooldescendants", 1 }, }; class CRPCConvertTable diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 9a7d9d53a0..2bd52eadbc 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -8,6 +8,7 @@ #include "chain.h" #include "chainparams.h" #include "consensus/consensus.h" +#include "consensus/params.h" #include "consensus/validation.h" #include "core_io.h" #include "init.h" @@ -303,6 +304,15 @@ static UniValue BIP22ValidationResult(const CValidationState& state) return "valid?"; } +std::string gbt_vb_name(const Consensus::DeploymentPos pos) { + const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos]; + std::string s = vbinfo.name; + if (!vbinfo.gbt_force) { + s.insert(s.begin(), '!'); + } + return s; +} + UniValue getblocktemplate(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) @@ -310,7 +320,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) "getblocktemplate ( \"jsonrequestobject\" )\n" "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" "It returns data needed to construct a block to work on.\n" - "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" + "For full specification, see BIPs 22 and 9:\n" + " https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n" + " https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n" "\nArguments:\n" "1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n" @@ -326,6 +338,12 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) "\nResult:\n" "{\n" " \"version\" : n, (numeric) The block version\n" + " \"rules\" : [ \"rulename\", ... ], (array of strings) specific block rules that are to be enforced\n" + " \"vbavailable\" : { (json object) set of pending, supported versionbit (BIP 9) softfork deployments\n" + " \"rulename\" : bitnumber (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule\n" + " ,...\n" + " },\n" + " \"vbrequired\" : n, (numeric) bit mask of versionbits the server requires set in submissions\n" " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n" " \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n" " {\n" @@ -369,6 +387,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) std::string strMode = "template"; UniValue lpval = NullUniValue; + std::set<std::string> setClientRules; + int64_t nMaxVersionPreVB = -1; if (params.size() > 0) { const UniValue& oparam = params[0].get_obj(); @@ -412,6 +432,20 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) TestBlockValidity(state, Params(), block, pindexPrev, false, true); return BIP22ValidationResult(state); } + + const UniValue& aClientRules = find_value(oparam, "rules"); + if (aClientRules.isArray()) { + for (unsigned int i = 0; i < aClientRules.size(); ++i) { + const UniValue& v = aClientRules[i]; + setClientRules.insert(v.get_str()); + } + } else { + // NOTE: It is important that this NOT be read if versionbits is supported + const UniValue& uvMaxVersion = find_value(oparam, "maxversion"); + if (uvMaxVersion.isNum()) { + nMaxVersionPreVB = uvMaxVersion.get_int64(); + } + } } if (strMode != "template") @@ -501,9 +535,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) pindexPrev = pindexPrevNew; } CBlock* pblock = &pblocktemplate->block; // pointer for convenience + const Consensus::Params& consensusParams = Params().GetConsensus(); // Update nTime - UpdateTime(pblock, Params().GetConsensus(), pindexPrev); + UpdateTime(pblock, consensusParams, pindexPrev); pblock->nNonce = 0; UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); @@ -544,17 +579,69 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); - static UniValue aMutable(UniValue::VARR); - if (aMutable.empty()) - { - aMutable.push_back("time"); - aMutable.push_back("transactions"); - aMutable.push_back("prevblock"); - } + UniValue aMutable(UniValue::VARR); + aMutable.push_back("time"); + aMutable.push_back("transactions"); + aMutable.push_back("prevblock"); UniValue result(UniValue::VOBJ); result.push_back(Pair("capabilities", aCaps)); + + UniValue aRules(UniValue::VARR); + UniValue vbavailable(UniValue::VOBJ); + for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++i) { + Consensus::DeploymentPos pos = Consensus::DeploymentPos(i); + ThresholdState state = VersionBitsState(pindexPrev, consensusParams, pos, versionbitscache); + switch (state) { + case THRESHOLD_DEFINED: + case THRESHOLD_FAILED: + // Not exposed to GBT at all + break; + case THRESHOLD_LOCKED_IN: + // Ensure bit is set in block version + pblock->nVersion |= VersionBitsMask(consensusParams, pos); + // FALL THROUGH to get vbavailable set... + case THRESHOLD_STARTED: + { + const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos]; + vbavailable.push_back(Pair(gbt_vb_name(pos), consensusParams.vDeployments[pos].bit)); + if (setClientRules.find(vbinfo.name) == setClientRules.end()) { + if (!vbinfo.gbt_force) { + // If the client doesn't support this, don't indicate it in the [default] version + pblock->nVersion &= ~VersionBitsMask(consensusParams, pos); + } + } + break; + } + case THRESHOLD_ACTIVE: + { + // Add to rules only + const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos]; + aRules.push_back(gbt_vb_name(pos)); + if (setClientRules.find(vbinfo.name) == setClientRules.end()) { + // Not supported by the client; make sure it's safe to proceed + if (!vbinfo.gbt_force) { + // If we do anything other than throw an exception here, be sure version/force isn't sent to old clients + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Support for '%s' rule requires explicit client support", vbinfo.name)); + } + } + break; + } + } + } result.push_back(Pair("version", pblock->nVersion)); + result.push_back(Pair("rules", aRules)); + result.push_back(Pair("vbavailable", vbavailable)); + result.push_back(Pair("vbrequired", int(0))); + + if (nMaxVersionPreVB >= 2) { + // If VB is supported by the client, nMaxVersionPreVB is -1, so we won't get here + // Because BIP 34 changed how the generation transaction is serialised, we can only use version/force back to v2 blocks + // This is safe to do [otherwise-]unconditionally only because we are throwing an exception above if a non-force deployment gets activated + // Note that this can probably also be removed entirely after the first BIP9 non-force deployment (ie, probably segwit) gets activated + aMutable.push_back("version/force"); + } + result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("transactions", transactions)); result.push_back(Pair("coinbaseaux", aux)); diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 36178bfb4c..cae964e46d 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -219,7 +219,7 @@ UniValue addnode(const UniValue& params, bool fHelp) if (strCommand == "onetry") { CAddress addr; - OpenNetworkConnection(addr, NULL, strNode.c_str()); + OpenNetworkConnection(addr, false, NULL, strNode.c_str()); return NullUniValue; } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 483fe746ca..992914f88c 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -334,6 +334,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) " {\n" " \"txid\":\"id\", (string, required) The transaction id\n" " \"vout\":n (numeric, required) The output number\n" + " \"sequence\":n (numeric, optional) The sequence number\n" " }\n" " ,...\n" " ]\n" @@ -384,6 +385,12 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); uint32_t nSequence = (rawTx.nLockTime ? std::numeric_limits<uint32_t>::max() - 1 : std::numeric_limits<uint32_t>::max()); + + // set the sequence number if passed in the parameters object + const UniValue& sequenceObj = find_value(o, "sequence"); + if (sequenceObj.isNum()) + nSequence = sequenceObj.get_int(); + CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence); rawTx.vin.push_back(in); @@ -675,7 +682,12 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) UniValue prevOut = p.get_obj(); - RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)); + RPCTypeCheckObj(prevOut, + { + {"txid", UniValueType(UniValue::VSTR)}, + {"vout", UniValueType(UniValue::VNUM)}, + {"scriptPubKey", UniValueType(UniValue::VSTR)}, + }); uint256 txid = ParseHashO(prevOut, "txid"); @@ -703,7 +715,13 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) // if redeemScript given and not using the local wallet (private keys // given), add redeemScript to the tempKeystore so it can be signed: if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) { - RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)("redeemScript",UniValue::VSTR)); + RPCTypeCheckObj(prevOut, + { + {"txid", UniValueType(UniValue::VSTR)}, + {"vout", UniValueType(UniValue::VNUM)}, + {"scriptPubKey", UniValueType(UniValue::VSTR)}, + {"redeemScript", UniValueType(UniValue::VSTR)}, + }); UniValue v = find_value(prevOut, "redeemScript"); if (!v.isNull()) { vector<unsigned char> rsData(ParseHexV(v, "redeemScript")); @@ -743,6 +761,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) // Script verification errors UniValue vErrors(UniValue::VARR); + // Use CTransaction for the constant parts of the + // transaction to avoid rehashing. + const CTransaction txConst(mergedTx); // Sign what we can: for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { CTxIn& txin = mergedTx.vin[i]; @@ -760,10 +781,10 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) // ... and merge in other signatures: BOOST_FOREACH(const CMutableTransaction& txv, txVariants) { - txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); + txin.scriptSig = CombineSignatures(prevPubKey, txConst, i, txin.scriptSig, txv.vin[i].scriptSig); } ScriptError serror = SCRIPT_ERR_OK; - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) { + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i), &serror)) { TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); } } diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index d06a9142b6..23149baa6d 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -88,20 +88,18 @@ void RPCTypeCheck(const UniValue& params, } void RPCTypeCheckObj(const UniValue& o, - const map<string, UniValue::VType>& typesExpected, - bool fAllowNull, - bool fStrict) + const map<string, UniValueType>& typesExpected, + bool fAllowNull, + bool fStrict) { - BOOST_FOREACH(const PAIRTYPE(string, UniValue::VType)& t, typesExpected) - { + for (const auto& t : typesExpected) { const UniValue& v = find_value(o, t.first); if (!fAllowNull && v.isNull()) throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first)); - if (!((v.type() == t.second) || (fAllowNull && (v.isNull())))) - { + if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) { string err = strprintf("Expected type %s for %s, got %s", - uvTypeName(t.second), t.first, uvTypeName(v.type())); + uvTypeName(t.second.type), t.first, uvTypeName(v.type())); throw JSONRPCError(RPC_TYPE_ERROR, err); } } diff --git a/src/rpc/server.h b/src/rpc/server.h index b471336617..b5ccc153d0 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -32,6 +32,15 @@ namespace RPCServer class CBlockIndex; class CNetAddr; +/** Wrapper for UniValue::VType, which includes typeAny: + * Used to denote don't care type. Only used by RPCTypeCheckObj */ +struct UniValueType { + UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {} + UniValueType() : typeAny(true) {} + bool typeAny; + UniValue::VType type; +}; + class JSONRequest { public: @@ -60,17 +69,17 @@ bool RPCIsInWarmup(std::string *statusOut); /** * Type-check arguments; throws JSONRPCError if wrong type given. Does not check that * the right number of arguments are passed, just that any passed are the correct type. - * Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type)); */ void RPCTypeCheck(const UniValue& params, const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false); /* Check for expected keys/value types in an Object. - Use like: RPCTypeCheckObj(object, boost::assign::map_list_of("name", str_type)("value", int_type)); */ void RPCTypeCheckObj(const UniValue& o, - const std::map<std::string, UniValue::VType>& typesExpected, bool fAllowNull=false, bool fStrict=false); + const std::map<std::string, UniValueType>& typesExpected, + bool fAllowNull = false, + bool fStrict = false); /** Opaque base class for timers returned by NewTimerFunc. * This provides no methods at the moment, but makes sure that delete diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index e5a2e28b2e..01eb2aee9e 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -79,7 +79,7 @@ class TestAddrTypeVisitor : public boost::static_visitor<bool> private: std::string exp_addrType; public: - TestAddrTypeVisitor(const std::string &exp_addrType) : exp_addrType(exp_addrType) { } + TestAddrTypeVisitor(const std::string &_exp_addrType) : exp_addrType(_exp_addrType) { } bool operator()(const CKeyID &id) const { return (exp_addrType == "pubkey"); @@ -100,7 +100,7 @@ class TestPayloadVisitor : public boost::static_visitor<bool> private: std::vector<unsigned char> exp_payload; public: - TestPayloadVisitor(std::vector<unsigned char> &exp_payload) : exp_payload(exp_payload) { } + TestPayloadVisitor(std::vector<unsigned char> &_exp_payload) : exp_payload(_exp_payload) { } bool operator()(const CKeyID &id) const { uint160 exp_key(exp_payload); diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json index 3bf80ca434..5cb383de85 100644 --- a/src/test/data/bitcoin-util-test.json +++ b/src/test/data/bitcoin-util-test.json @@ -86,5 +86,18 @@ "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o", "outdata=54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"], "output_cmp": "txcreatedata2.hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:4294967293", + "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"], + "output_cmp": "txcreatedata_seq0.hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:1"], + "output_cmp": "txcreatedata_seq1.hex" } ] diff --git a/src/test/data/txcreatedata_seq0.hex b/src/test/data/txcreatedata_seq0.hex new file mode 100644 index 0000000000..db02b5e4a4 --- /dev/null +++ b/src/test/data/txcreatedata_seq0.hex @@ -0,0 +1 @@ +01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000 diff --git a/src/test/data/txcreatedata_seq1.hex b/src/test/data/txcreatedata_seq1.hex new file mode 100644 index 0000000000..4cedcd975c --- /dev/null +++ b/src/test/data/txcreatedata_seq1.hex @@ -0,0 +1 @@ +01000000021f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff1f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000010000000180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000 diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index 8baaf3645f..82d61209b5 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -47,17 +47,58 @@ BOOST_AUTO_TEST_CASE(murmurhash3) #undef T } +/* + SipHash-2-4 output with + k = 00 01 02 ... + and + in = (empty string) + in = 00 (1 byte) + in = 00 01 (2 bytes) + in = 00 01 02 (3 bytes) + ... + in = 00 01 02 ... 3e (63 bytes) + + from: https://131002.net/siphash/siphash24.c +*/ +uint64_t siphash_4_2_testvec[] = { + 0x726fdb47dd0e0e31, 0x74f839c593dc67fd, 0x0d6c8009d9a94f5a, 0x85676696d7fb7e2d, + 0xcf2794e0277187b7, 0x18765564cd99a68d, 0xcbc9466e58fee3ce, 0xab0200f58b01d137, + 0x93f5f5799a932462, 0x9e0082df0ba9e4b0, 0x7a5dbbc594ddb9f3, 0xf4b32f46226bada7, + 0x751e8fbc860ee5fb, 0x14ea5627c0843d90, 0xf723ca908e7af2ee, 0xa129ca6149be45e5, + 0x3f2acc7f57c29bdb, 0x699ae9f52cbe4794, 0x4bc1b3f0968dd39c, 0xbb6dc91da77961bd, + 0xbed65cf21aa2ee98, 0xd0f2cbb02e3b67c7, 0x93536795e3a33e88, 0xa80c038ccd5ccec8, + 0xb8ad50c6f649af94, 0xbce192de8a85b8ea, 0x17d835b85bbb15f3, 0x2f2e6163076bcfad, + 0xde4daaaca71dc9a5, 0xa6a2506687956571, 0xad87a3535c49ef28, 0x32d892fad841c342, + 0x7127512f72f27cce, 0xa7f32346f95978e3, 0x12e0b01abb051238, 0x15e034d40fa197ae, + 0x314dffbe0815a3b4, 0x027990f029623981, 0xcadcd4e59ef40c4d, 0x9abfd8766a33735c, + 0x0e3ea96b5304a7d0, 0xad0c42d6fc585992, 0x187306c89bc215a9, 0xd4a60abcf3792b95, + 0xf935451de4f21df2, 0xa9538f0419755787, 0xdb9acddff56ca510, 0xd06c98cd5c0975eb, + 0xe612a3cb9ecba951, 0xc766e62cfcadaf96, 0xee64435a9752fe72, 0xa192d576b245165a, + 0x0a8787bf8ecb74b2, 0x81b3e73d20b49b6f, 0x7fa8220ba3b2ecea, 0x245731c13ca42499, + 0xb78dbfaf3a8d83bd, 0xea1ad565322a1a0b, 0x60e61c23a3795013, 0x6606d7e446282b93, + 0x6ca4ecb15c5f91e1, 0x9f626da15c9625f3, 0xe51b38608ef25f57, 0x958a324ceb064572 +}; + BOOST_AUTO_TEST_CASE(siphash) { CSipHasher hasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x726fdb47dd0e0e31ull); - hasher.Write(0x0706050403020100ULL); + static const unsigned char t0[1] = {0}; + hasher.Write(t0, 1); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x74f839c593dc67fdull); + static const unsigned char t1[7] = {1,2,3,4,5,6,7}; + hasher.Write(t1, 7); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x93f5f5799a932462ull); hasher.Write(0x0F0E0D0C0B0A0908ULL); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x3f2acc7f57c29bdbull); - hasher.Write(0x1716151413121110ULL); - BOOST_CHECK_EQUAL(hasher.Finalize(), 0xb8ad50c6f649af94ull); - hasher.Write(0x1F1E1D1C1B1A1918ULL); + static const unsigned char t2[2] = {16,17}; + hasher.Write(t2, 2); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x4bc1b3f0968dd39cull); + static const unsigned char t3[9] = {18,19,20,21,22,23,24,25,26}; + hasher.Write(t3, 9); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x2f2e6163076bcfadull); + static const unsigned char t4[5] = {27,28,29,30,31}; + hasher.Write(t4, 5); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x7127512f72f27cceull); hasher.Write(0x2726252423222120ULL); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x0e3ea96b5304a7d0ull); @@ -65,6 +106,22 @@ BOOST_AUTO_TEST_CASE(siphash) BOOST_CHECK_EQUAL(hasher.Finalize(), 0xe612a3cb9ecba951ull); BOOST_CHECK_EQUAL(SipHashUint256(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL, uint256S("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100")), 0x7127512f72f27cceull); + + // Check test vectors from spec, one byte at a time + CSipHasher hasher2(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL); + for (uint8_t x=0; x<ARRAYLEN(siphash_4_2_testvec); ++x) + { + BOOST_CHECK_EQUAL(hasher2.Finalize(), siphash_4_2_testvec[x]); + hasher2.Write(&x, 1); + } + // Check test vectors from spec, eight bytes at a time + CSipHasher hasher3(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL); + for (uint8_t x=0; x<ARRAYLEN(siphash_4_2_testvec); x+=8) + { + BOOST_CHECK_EQUAL(hasher3.Finalize(), siphash_4_2_testvec[x]); + hasher3.Write(uint64_t(x)|(uint64_t(x+1)<<8)|(uint64_t(x+2)<<16)|(uint64_t(x+3)<<24)| + (uint64_t(x+4)<<32)|(uint64_t(x+5)<<40)|(uint64_t(x+6)<<48)|(uint64_t(x+7)<<56)); + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 469862518c..3f5f0ee98b 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -385,8 +385,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) SetMockTime(0); mempool.clear(); - BOOST_FOREACH(CTransaction *tx, txFirst) - delete tx; + BOOST_FOREACH(CTransaction *_tx, txFirst) + delete _tx; fCheckpointsEnabled = true; } diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index 2f3f607889..74ffe0cc74 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -37,8 +37,8 @@ BOOST_AUTO_TEST_CASE(pmt_test1) seed_insecure_rand(false); static const unsigned int nTxCounts[] = {1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095}; - for (int n = 0; n < 12; n++) { - unsigned int nTx = nTxCounts[n]; + for (int i = 0; i < 12; i++) { + unsigned int nTx = nTxCounts[i]; // build a block with some dummy transactions CBlock block; diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp index 644c3da213..2b00e6f567 100644 --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -74,9 +74,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) // 9/10 blocks add 2nd highest and so on until ... // 1/10 blocks add lowest fee/pri transactions while (txHashes[9-h].size()) { - CTransaction btx; - if (mpool.lookup(txHashes[9-h].back(), btx)) - block.push_back(btx); + std::shared_ptr<const CTransaction> ptx = mpool.get(txHashes[9-h].back()); + if (ptx) + block.push_back(*ptx); txHashes[9-h].pop_back(); } } @@ -160,9 +160,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) // Estimates should still not be below original for (int j = 0; j < 10; j++) { while(txHashes[j].size()) { - CTransaction btx; - if (mpool.lookup(txHashes[j].back(), btx)) - block.push_back(btx); + std::shared_ptr<const CTransaction> ptx = mpool.get(txHashes[j].back()); + if (ptx) + block.push_back(*ptx); txHashes[j].pop_back(); } } @@ -181,9 +181,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) tx.vin[0].prevout.n = 10000*blocknum+100*j+k; uint256 hash = tx.GetHash(); mpool.addUnchecked(hash, entry.Fee(feeV[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool)); - CTransaction btx; - if (mpool.lookup(hash, btx)) - block.push_back(btx); + std::shared_ptr<const CTransaction> ptx = mpool.get(hash); + if (ptx) + block.push_back(*ptx); } } mpool.removeForBlock(block, ++blocknum, dummyConflicted); diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp index b39b903530..d1407c1da9 100644 --- a/src/test/prevector_tests.cpp +++ b/src/test/prevector_tests.cpp @@ -192,8 +192,8 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt) if (((r >> 21) % 32) == 7) { int values[4]; int num = 1 + (insecure_rand() % 4); - for (int i = 0; i < num; i++) { - values[i] = insecure_rand(); + for (int k = 0; k < num; k++) { + values[k] = insecure_rand(); } test.insert_range(insecure_rand() % (test.size() + 1), values, values + num); } diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index b99f952a0d..e467a4171d 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -376,6 +376,69 @@ BOOST_AUTO_TEST_CASE(test_ParseInt64) BOOST_CHECK(!ParseInt64("32482348723847471234", NULL)); } +BOOST_AUTO_TEST_CASE(test_ParseUInt32) +{ + uint32_t n; + // Valid values + BOOST_CHECK(ParseUInt32("1234", NULL)); + BOOST_CHECK(ParseUInt32("0", &n) && n == 0); + BOOST_CHECK(ParseUInt32("1234", &n) && n == 1234); + BOOST_CHECK(ParseUInt32("01234", &n) && n == 1234); // no octal + BOOST_CHECK(ParseUInt32("2147483647", &n) && n == 2147483647); + BOOST_CHECK(ParseUInt32("2147483648", &n) && n == (uint32_t)2147483648); + BOOST_CHECK(ParseUInt32("4294967295", &n) && n == (uint32_t)4294967295); + // Invalid values + BOOST_CHECK(!ParseUInt32("", &n)); + BOOST_CHECK(!ParseUInt32(" 1", &n)); // no padding inside + BOOST_CHECK(!ParseUInt32(" -1", &n)); + BOOST_CHECK(!ParseUInt32("1 ", &n)); + BOOST_CHECK(!ParseUInt32("1a", &n)); + BOOST_CHECK(!ParseUInt32("aap", &n)); + BOOST_CHECK(!ParseUInt32("0x1", &n)); // no hex + BOOST_CHECK(!ParseUInt32("0x1", &n)); // no hex + const char test_bytes[] = {'1', 0, '1'}; + std::string teststr(test_bytes, sizeof(test_bytes)); + BOOST_CHECK(!ParseUInt32(teststr, &n)); // no embedded NULs + // Overflow and underflow + BOOST_CHECK(!ParseUInt32("-2147483648", &n)); + BOOST_CHECK(!ParseUInt32("4294967296", &n)); + BOOST_CHECK(!ParseUInt32("-1234", &n)); + BOOST_CHECK(!ParseUInt32("-32482348723847471234", NULL)); + BOOST_CHECK(!ParseUInt32("32482348723847471234", NULL)); +} + +BOOST_AUTO_TEST_CASE(test_ParseUInt64) +{ + uint64_t n; + // Valid values + BOOST_CHECK(ParseUInt64("1234", NULL)); + BOOST_CHECK(ParseUInt64("0", &n) && n == 0LL); + BOOST_CHECK(ParseUInt64("1234", &n) && n == 1234LL); + BOOST_CHECK(ParseUInt64("01234", &n) && n == 1234LL); // no octal + BOOST_CHECK(ParseUInt64("2147483647", &n) && n == 2147483647LL); + BOOST_CHECK(ParseUInt64("9223372036854775807", &n) && n == 9223372036854775807ULL); + BOOST_CHECK(ParseUInt64("9223372036854775808", &n) && n == 9223372036854775808ULL); + BOOST_CHECK(ParseUInt64("18446744073709551615", &n) && n == 18446744073709551615ULL); + // Invalid values + BOOST_CHECK(!ParseUInt64("", &n)); + BOOST_CHECK(!ParseUInt64(" 1", &n)); // no padding inside + BOOST_CHECK(!ParseUInt64(" -1", &n)); + BOOST_CHECK(!ParseUInt64("1 ", &n)); + BOOST_CHECK(!ParseUInt64("1a", &n)); + BOOST_CHECK(!ParseUInt64("aap", &n)); + BOOST_CHECK(!ParseUInt64("0x1", &n)); // no hex + const char test_bytes[] = {'1', 0, '1'}; + std::string teststr(test_bytes, sizeof(test_bytes)); + BOOST_CHECK(!ParseUInt64(teststr, &n)); // no embedded NULs + // Overflow and underflow + BOOST_CHECK(!ParseUInt64("-9223372036854775809", NULL)); + BOOST_CHECK(!ParseUInt64("18446744073709551616", NULL)); + BOOST_CHECK(!ParseUInt64("-32482348723847471234", NULL)); + BOOST_CHECK(!ParseUInt64("-2147483648", &n)); + BOOST_CHECK(!ParseUInt64("-9223372036854775808", &n)); + BOOST_CHECK(!ParseUInt64("-1234", &n)); +} + BOOST_AUTO_TEST_CASE(test_ParseDouble) { double n; diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 47d834c7b4..0d6b655675 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -574,7 +574,15 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl * password: "password" */ std::string torpassword = GetArg("-torpassword", ""); - if (methods.count("NULL")) { + if (!torpassword.empty()) { + if (methods.count("HASHEDPASSWORD")) { + LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n"); + boost::replace_all(torpassword, "\"", "\\\""); + conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2)); + } else { + LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n"); + } + } else if (methods.count("NULL")) { LogPrint("tor", "tor: Using NULL authentication\n"); conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2)); } else if (methods.count("SAFECOOKIE")) { @@ -595,13 +603,7 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl } } } else if (methods.count("HASHEDPASSWORD")) { - if (!torpassword.empty()) { - LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n"); - boost::replace_all(torpassword, "\"", "\\\""); - conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2)); - } else { - LogPrintf("tor: Password authentication required, but no password provided with -torpassword\n"); - } + LogPrintf("tor: The only supported authentication mechanism left is password, but no password provided with -torpassword\n"); } else { LogPrintf("tor: No supported authentication method\n"); } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index f44e450363..205ffd6379 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -23,18 +23,18 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, bool poolHasNoInputsOf, CAmount _inChainInputValue, bool _spendsCoinbase, unsigned int _sigOps, LockPoints lp): - tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), + tx(std::make_shared<CTransaction>(_tx)), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp) { - nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - nModSize = tx.CalculateModifiedSize(nTxSize); - nUsageSize = RecursiveDynamicUsage(tx); + nTxSize = ::GetSerializeSize(_tx, SER_NETWORK, PROTOCOL_VERSION); + nModSize = _tx.CalculateModifiedSize(nTxSize); + nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx); nCountWithDescendants = 1; nSizeWithDescendants = nTxSize; nModFeesWithDescendants = nFee; - CAmount nValueIn = tx.GetValueOut()+nFee; + CAmount nValueIn = _tx.GetValueOut()+nFee; assert(inChainInputValue <= nValueIn); feeDelta = 0; @@ -768,50 +768,76 @@ bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb namespace { class DepthAndScoreComparator { - CTxMemPool *mp; public: - DepthAndScoreComparator(CTxMemPool *mempool) : mp(mempool) {} - bool operator()(const uint256& a, const uint256& b) { return mp->CompareDepthAndScore(a, b); } + bool operator()(const CTxMemPool::indexed_transaction_set::const_iterator& a, const CTxMemPool::indexed_transaction_set::const_iterator& b) + { + uint64_t counta = a->GetCountWithAncestors(); + uint64_t countb = b->GetCountWithAncestors(); + if (counta == countb) { + return CompareTxMemPoolEntryByScore()(*a, *b); + } + return counta < countb; + } }; } -void CTxMemPool::queryHashes(vector<uint256>& vtxid) +std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::GetSortedDepthAndScore() const { - vtxid.clear(); + std::vector<indexed_transaction_set::const_iterator> iters; + AssertLockHeld(cs); + + iters.reserve(mapTx.size()); + for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) { + iters.push_back(mi); + } + std::sort(iters.begin(), iters.end(), DepthAndScoreComparator()); + return iters; +} + +void CTxMemPool::queryHashes(vector<uint256>& vtxid) +{ LOCK(cs); + auto iters = GetSortedDepthAndScore(); + + vtxid.clear(); vtxid.reserve(mapTx.size()); - for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) - vtxid.push_back(mi->GetTx().GetHash()); - std::sort(vtxid.begin(), vtxid.end(), DepthAndScoreComparator(this)); + for (auto it : iters) { + vtxid.push_back(it->GetTx().GetHash()); + } } - -bool CTxMemPool::lookup(uint256 hash, CTransaction& result, int64_t& time) const +std::vector<TxMempoolInfo> CTxMemPool::infoAll() const { LOCK(cs); - indexed_transaction_set::const_iterator i = mapTx.find(hash); - if (i == mapTx.end()) return false; - result = i->GetTx(); - time = i->GetTime(); - return true; + auto iters = GetSortedDepthAndScore(); + + std::vector<TxMempoolInfo> ret; + ret.reserve(mapTx.size()); + for (auto it : iters) { + ret.push_back(TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize())}); + } + + return ret; } -bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const +std::shared_ptr<const CTransaction> CTxMemPool::get(const uint256& hash) const { - int64_t time; - return CTxMemPool::lookup(hash, result, time); + LOCK(cs); + indexed_transaction_set::const_iterator i = mapTx.find(hash); + if (i == mapTx.end()) + return nullptr; + return i->GetSharedTx(); } -bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const +TxMempoolInfo CTxMemPool::info(const uint256& hash) const { LOCK(cs); indexed_transaction_set::const_iterator i = mapTx.find(hash); if (i == mapTx.end()) - return false; - feeRate = CFeeRate(i->GetFee(), i->GetTxSize()); - return true; + return TxMempoolInfo(); + return TxMempoolInfo{i->GetSharedTx(), i->GetTime(), CFeeRate(i->GetFee(), i->GetTxSize())}; } CFeeRate CTxMemPool::estimateFee(int nBlocks) const @@ -924,9 +950,9 @@ 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. - CTransaction tx; - if (mempool.lookup(txid, tx)) { - coins = CCoins(tx, MEMPOOL_HEIGHT); + shared_ptr<const CTransaction> ptx = mempool.get(txid); + if (ptx) { + coins = CCoins(*ptx, MEMPOOL_HEIGHT); return true; } return (base->GetCoins(txid, coins) && !coins.IsPruned()); diff --git a/src/txmempool.h b/src/txmempool.h index 3cf84159cc..f0e9b2e2c6 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -7,6 +7,7 @@ #define BITCOIN_TXMEMPOOL_H #include <list> +#include <memory> #include <set> #include "amount.h" @@ -75,7 +76,7 @@ class CTxMemPool; class CTxMemPoolEntry { private: - CTransaction tx; + std::shared_ptr<const CTransaction> tx; CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups size_t nTxSize; //!< ... and avoid recomputing tx size size_t nModSize; //!< ... and modified size for priority @@ -112,7 +113,8 @@ public: unsigned int nSigOps, LockPoints lp); CTxMemPoolEntry(const CTxMemPoolEntry& other); - const CTransaction& GetTx() const { return this->tx; } + const CTransaction& GetTx() const { return *this->tx; } + std::shared_ptr<const CTransaction> GetSharedTx() const { return this->tx; } /** * Fast calculation of lower bound of current priority as update * from entry priority. Only inputs that were originally in-chain will age. @@ -308,6 +310,21 @@ struct ancestor_score {}; class CBlockPolicyEstimator; /** + * Information about a mempool transaction. + */ +struct TxMempoolInfo +{ + /** The transaction itself */ + std::shared_ptr<const CTransaction> tx; + + /** Time the transaction entered the mempool. */ + int64_t nTime; + + /** Feerate of the transaction. */ + CFeeRate feeRate; +}; + +/** * CTxMemPool stores valid-according-to-the-current-best-chain * transactions that may be included in the next block. * @@ -464,6 +481,8 @@ private: void UpdateParent(txiter entry, txiter parent, bool add); void UpdateChild(txiter entry, txiter child, bool add); + std::vector<indexed_transaction_set::const_iterator> GetSortedDepthAndScore() const; + public: indirectmap<COutPoint, const CTransaction*> mapNextTx; std::map<uint256, std::pair<double, CAmount> > mapDeltas; @@ -588,9 +607,9 @@ public: return (mapTx.count(hash) != 0); } - bool lookup(uint256 hash, CTransaction& result) const; - bool lookup(uint256 hash, CTransaction& result, int64_t& time) const; - bool lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const; + std::shared_ptr<const CTransaction> get(const uint256& hash) const; + TxMempoolInfo info(const uint256& hash) const; + std::vector<TxMempoolInfo> infoAll() const; /** Estimate fee rate needed to get into the next nBlocks * If no answer can be given at nBlocks, return an estimate diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 0f9334cbe3..5ffdb3be15 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -461,6 +461,40 @@ bool ParseInt64(const std::string& str, int64_t *out) n <= std::numeric_limits<int64_t>::max(); } +bool ParseUInt32(const std::string& str, uint32_t *out) +{ + if (!ParsePrechecks(str)) + return false; + if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoul accepts these by default if they fit in the range + return false; + char *endp = NULL; + errno = 0; // strtoul will not set errno if valid + unsigned long int n = strtoul(str.c_str(), &endp, 10); + if(out) *out = (uint32_t)n; + // Note that strtoul returns a *unsigned long int*, so even if it doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *uint32_t*. On 64-bit + // platforms the size of these types may be different. + return endp && *endp == 0 && !errno && + n <= std::numeric_limits<uint32_t>::max(); +} + +bool ParseUInt64(const std::string& str, uint64_t *out) +{ + if (!ParsePrechecks(str)) + return false; + if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoull accepts these by default if they fit in the range + return false; + char *endp = NULL; + errno = 0; // strtoull will not set errno if valid + unsigned long long int n = strtoull(str.c_str(), &endp, 10); + if(out) *out = (uint64_t)n; + // Note that strtoull returns a *unsigned long long int*, so even if it doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *uint64_t*. + return endp && *endp == 0 && !errno && + n <= std::numeric_limits<uint64_t>::max(); +} + + bool ParseDouble(const std::string& str, double *out) { if (!ParsePrechecks(str)) diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index d40613cfc4..5744f78c6e 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -71,6 +71,20 @@ bool ParseInt32(const std::string& str, int32_t *out); bool ParseInt64(const std::string& str, int64_t *out); /** + * Convert decimal string to unsigned 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 occurred. + */ +bool ParseUInt32(const std::string& str, uint32_t *out); + +/** + * Convert decimal string to unsigned 64-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 occurred. + */ +bool ParseUInt64(const std::string& str, uint64_t *out); + +/** * Convert string to double with strict parse error feedback. * @returns true if the entire string could be parsed as valid double, * false if not the entire string could be parsed or when overflow or underflow occurred. diff --git a/src/versionbits.cpp b/src/versionbits.cpp index 78feb8ab0c..043819c654 100644 --- a/src/versionbits.cpp +++ b/src/versionbits.cpp @@ -4,6 +4,19 @@ #include "versionbits.h" +#include "consensus/params.h" + +const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = { + { + /*.name =*/ "testdummy", + /*.gbt_force =*/ true, + }, + { + /*.name =*/ "csv", + /*.gbt_force =*/ true, + } +}; + ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const { int nPeriod = Period(params); diff --git a/src/versionbits.h b/src/versionbits.h index 04f4738272..ede2dcdda8 100644 --- a/src/versionbits.h +++ b/src/versionbits.h @@ -30,6 +30,15 @@ enum ThresholdState { // will either be NULL or a block with (height + 1) % Period() == 0. typedef std::map<const CBlockIndex*, ThresholdState> ThresholdConditionCache; +struct BIP9DeploymentInfo { + /** Deployment name */ + const char *name; + /** Whether GBT clients can safely ignore this rule in simplified usage */ + bool gbt_force; +}; + +extern const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[]; + /** * Abstract class that implements BIP9-style threshold logic, and caches results. */ diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index bb40cf7245..14c2e31d95 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -590,7 +590,7 @@ UniValue dumpwallet(const UniValue& params, bool fHelp) std::sort(vKeyBirth.begin(), vKeyBirth.end()); // produce output - file << strprintf("# Wallet dump created by Bitcoin %s (%s)\n", CLIENT_BUILD, CLIENT_DATE); + file << strprintf("# Wallet dump created by Bitcoin %s\n", CLIENT_BUILD); file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime())); file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString()); file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime())); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5e6afcd7cb..2d4e95911d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2069,7 +2069,11 @@ UniValue lockunspent(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object"); const UniValue& o = output.get_obj(); - RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)); + RPCTypeCheckObj(o, + { + {"txid", UniValueType(UniValue::VSTR)}, + {"vout", UniValueType(UniValue::VNUM)}, + }); string txid = find_value(o, "txid").get_str(); if (!IsHex(txid)) @@ -2369,13 +2373,13 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) " \"changePosition\" (numeric, optional, default random) The index of the change output\n" " \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n" " \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n" - " \"feeRate\" (numeric, optional, default 0=estimate) Set a specific feerate (fee per KB)\n" + " \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific feerate (" + CURRENCY_UNIT + " per KB)\n" " }\n" " for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n" "\nResult:\n" "{\n" " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n" - " \"fee\": n, (numeric) Fee the resulting transaction pays\n" + " \"fee\": n, (numeric) Fee in " + CURRENCY_UNIT + " the resulting transaction pays\n" " \"changepos\": n (numeric) The position of the added change output, or -1\n" "}\n" "\"hex\" \n" @@ -2409,7 +2413,15 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) UniValue options = params[1]; - RPCTypeCheckObj(options, boost::assign::map_list_of("changeAddress", UniValue::VSTR)("changePosition", UniValue::VNUM)("includeWatching", UniValue::VBOOL)("lockUnspents", UniValue::VBOOL)("feeRate", UniValue::VNUM), true, true); + RPCTypeCheckObj(options, + { + {"changeAddress", UniValueType(UniValue::VSTR)}, + {"changePosition", UniValueType(UniValue::VNUM)}, + {"includeWatching", UniValueType(UniValue::VBOOL)}, + {"lockUnspents", UniValueType(UniValue::VBOOL)}, + {"feeRate", UniValueType()}, // will be checked below + }, + true, true); if (options.exists("changeAddress")) { CBitcoinAddress address(options["changeAddress"].get_str()); @@ -2431,7 +2443,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) if (options.exists("feeRate")) { - feeRate = CFeeRate(options["feeRate"].get_real()); + feeRate = CFeeRate(AmountFromValue(options["feeRate"])); overrideEstimatedFeerate = true; } } @@ -2445,7 +2457,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) if (origTx.vout.size() == 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output"); - if (changePosition != -1 && (changePosition < 0 || changePosition > origTx.vout.size())) + if (changePosition != -1 && (changePosition < 0 || (unsigned int)changePosition > origTx.vout.size())) throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds"); CMutableTransaction tx(origTx); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index f3d165472a..9faf21591f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2232,7 +2232,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt // Insert change txn at random position: nChangePosInOut = GetRandInt(txNew.vout.size()+1); } - else if (nChangePosInOut > txNew.vout.size()) + else if ((unsigned int)nChangePosInOut > txNew.vout.size()) { strFailReason = _("Change index out of range"); return false; |