diff options
130 files changed, 3279 insertions, 2543 deletions
diff --git a/.travis.yml b/.travis.yml index 34787669db..31b3d6d96e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ env: global: - MAKEJOBS=-j3 - RUN_TESTS=false + - CHECK_DOC=0 - BOOST_TEST_RANDOM=1$TRAVIS_BUILD_ID - CCACHE_SIZE=100M - CCACHE_TEMPDIR=/tmp/.ccache-temp @@ -35,7 +36,7 @@ matrix: fast_finish: true include: - compiler: ": ARM" - env: HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf" DEP_OPTS="NO_QT=1" GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" + env: HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf" DEP_OPTS="NO_QT=1" CHECK_DOC=1 GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" - compiler: ": Win32" env: HOST=i686-w64-mingw32 PPA="ppa:ubuntu-wine/ppa" PACKAGES="nsis gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev wine1.7 bc" RUN_TESTS=true GOAL="deploy" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" MAKEJOBS="-j2" - compiler: ": 32-bit + dash" @@ -57,6 +58,7 @@ install: - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES; fi before_script: - unset CC; unset CXX + - if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/check-doc.py; fi - mkdir -p depends/SDKs depends/sdk-sources - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi @@ -70,7 +72,6 @@ script: - 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 - - if [ "$RUN_TESTS" = "true" ]; then contrib/devtools/check-doc.py; fi - cd bitcoin-$HOST - ./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) - make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false ) @@ -15,7 +15,7 @@ out collectively by the network. Bitcoin Core is the name of open source software which enables the use of this currency. For more information, as well as an immediately useable, binary version of -the Bitcoin Core software, see https://www.bitcoin.org/en/download, or read the +the Bitcoin Core software, see https://bitcoin.org/en/download, or read the [original whitepaper](https://bitcoincore.org/bitcoin.pdf). License @@ -55,10 +55,10 @@ submit new unit tests for old code. Unit tests can be compiled and run There are also [regression and integration tests](/qa) of the RPC interface, written in Python, that are run automatically on the build server. -These tests can be run with: `qa/pull-tester/rpc-tests.py` +These tests can be run (if the [test dependencies](/qa) are installed) with: `qa/pull-tester/rpc-tests.py` The Travis CI system makes sure that every pull request is built for Windows -and Linux, OSX, and that unit and sanity tests are automatically run. +and Linux, OS X, and that unit and sanity tests are automatically run. ### Manual Quality Assurance (QA) Testing diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index 5fe12fda9b..efffa4887d 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -384,7 +384,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG],[ dnl qt version is set to 'auto' and the preferred version wasn't found. Now try the other. if test x$have_qt = xno && test x$bitcoin_qt_want_version = xauto; then - if test x$auto_priority_version = x$qt5; then + if test x$auto_priority_version = xqt5; then PKG_CHECK_MODULES([QT], [$qt4_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes; QT_LIB_PREFIX=Qt; bitcoin_qt_got_major_vers=4], [have_qt=no]) else PKG_CHECK_MODULES([QT], [$qt5_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes; QT_LIB_PREFIX=Qt5; bitcoin_qt_got_major_vers=5], [have_qt=no]) diff --git a/contrib/README.md b/contrib/README.md index fe77476037..9461539166 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -51,9 +51,5 @@ Test and Verify Tools ### [TestGen](/contrib/testgen) ### Utilities to generate test vectors for the data-driven Bitcoin tests. -### [Test Patches](/contrib/test-patches) ### -These patches are applied when the automated pull-tester -tests each pull and when master is tested using jenkins. - ### [Verify SF Binaries](/contrib/verifysfbinaries) ### This script attempts to download and verify the signature file SHA256SUMS.asc from SourceForge. diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index b4b6ed2909..1f2c4f9999 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -6,6 +6,7 @@ suites: architectures: - "amd64" packages: +- "curl" - "g++-multilib" - "git-core" - "pkg-config" diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 4a4592398b..6f68ae08ce 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -7,6 +7,7 @@ architectures: - "amd64" packages: - "ca-certificates" +- "curl" - "g++" - "git-core" - "pkg-config" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 233f5c5498..f0fbff3e10 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -6,6 +6,7 @@ suites: architectures: - "amd64" packages: +- "curl" - "g++" - "git-core" - "pkg-config" diff --git a/contrib/verifysfbinaries/README.md b/contrib/verifysfbinaries/README.md index 8c038865bd..1db3fe52fc 100644 --- a/contrib/verifysfbinaries/README.md +++ b/contrib/verifysfbinaries/README.md @@ -1,6 +1,6 @@ -### Verify SF Binaries ### +### Verify Binaries ### This script attempts to download the signature file `SHA256SUMS.asc` from https://bitcoin.org. It first checks if the signature passes, and then downloads the files specified in the file, and checks if the hashes of these files match those that are specified in the signature file. -The script returns 0 if everything passes the checks. It returns 1 if either the signature check or the hash check doesn't pass. If an error occurs the return value is 2.
\ No newline at end of file +The script returns 0 if everything passes the checks. It returns 1 if either the signature check or the hash check doesn't pass. If an error occurs the return value is 2. diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index cedbddc578..200d6ed22a 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -7,7 +7,7 @@ build_darwin_OTOOL: = $(shell xcrun -f otool) build_darwin_NM: = $(shell xcrun -f nm) build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) build_darwin_SHA256SUM = shasum -a 256 -build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -o +build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o #darwin host on darwin builder. overrides darwin host preferences. darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) diff --git a/depends/builders/linux.mk b/depends/builders/linux.mk index d6a304e4b4..b03f424010 100644 --- a/depends/builders/linux.mk +++ b/depends/builders/linux.mk @@ -1,2 +1,2 @@ build_linux_SHA256SUM = sha256sum -build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -o +build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o diff --git a/depends/config.guess b/depends/config.guess index fba6e87a0f..373a659a06 100755 --- a/depends/config.guess +++ b/depends/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2015 Free Software Foundation, Inc. +# Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2015-11-19' +timestamp='2016-02-11' # 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 @@ -27,7 +27,7 @@ timestamp='2015-11-19' # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to <config-patches@gnu.org>. @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2015 Free Software Foundation, Inc. +Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -237,6 +237,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; @@ -268,42 +272,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; + UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; + UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; + UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; + UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; + UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; + UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; + UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; + UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; + UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 @@ -376,16 +380,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build - SUN_ARCH="i386" + SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + 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) | \ grep IS_64BIT_ARCH >/dev/null then - SUN_ARCH="x86_64" + SUN_ARCH=x86_64 fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` @@ -410,7 +414,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} @@ -635,13 +639,13 @@ EOF sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi @@ -684,7 +688,7 @@ EOF test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = "hppa2.0w" ] + if [ ${HP_ARCH} = hppa2.0w ] then eval $set_cc_for_build @@ -700,9 +704,9 @@ EOF if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then - HP_ARCH="hppa2.0w" + HP_ARCH=hppa2.0w else - HP_ARCH="hppa64" + HP_ARCH=hppa64 fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} @@ -807,14 +811,14 @@ EOF echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) @@ -919,7 +923,7 @@ EOF EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) @@ -1285,7 +1289,7 @@ EOF UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; 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) | \ grep IS_64BIT_ARCH >/dev/null @@ -1309,7 +1313,7 @@ EOF exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then + if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi @@ -1340,7 +1344,7 @@ EOF # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - if test "$cputype" = "386"; then + if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" @@ -1394,7 +1398,7 @@ EOF echo ${UNAME_MACHINE}-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) - echo x86_64-unknown-onefs + echo x86_64-unknown-onefs exit ;; esac @@ -1405,9 +1409,9 @@ 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 - http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + 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;hb=HEAD + 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 diff --git a/depends/config.sub b/depends/config.sub index ea8747d30f..6223dde931 100755 --- a/depends/config.sub +++ b/depends/config.sub @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2015 Free Software Foundation, Inc. +# Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2015-11-22' +timestamp='2016-01-01' # 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 @@ -33,7 +33,7 @@ timestamp='2015-11-22' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -67,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>." version="\ GNU config.sub ($timestamp) -Copyright 1992-2015 Free Software Foundation, Inc. +Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -520,7 +520,7 @@ case $basic_machine in basic_machine=i386-pc os=-aros ;; - asmjs) + asmjs) basic_machine=asmjs-unknown ;; aux) @@ -1382,7 +1382,7 @@ case $os in | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk index 3d5a6df974..45fa03631f 100644 --- a/depends/packages/miniupnpc.mk +++ b/depends/packages/miniupnpc.mk @@ -1,8 +1,8 @@ package=miniupnpc -$(package)_version=1.9.20151026 +$(package)_version=1.9.20160209 $(package)_download_path=http://miniupnp.free.fr/files $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=f3cf9a5a31588a917d4d9237e5bc50f84d00c5aa48e27ed50d9b88dfa6a25d47 +$(package)_sha256_hash=572171eacc1d72537ce47b6f4571260757ab7bcfdaf54c3a55c7f88594d94b6f define $(package)_set_vars $(package)_build_opts=CC="$($(package)_cc)" diff --git a/depends/patches/boost/darwin_boost_atomic-1.patch b/depends/patches/boost/darwin_boost_atomic-1.patch deleted file mode 100644 index 97f59cb7e4..0000000000 --- a/depends/patches/boost/darwin_boost_atomic-1.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff --git a/include/boost/atomic/detail/cas128strong.hpp b/include/boost/atomic/detail/cas128strong.hpp -index 906c13e..dcb4d7d 100644 ---- a/include/boost/atomic/detail/cas128strong.hpp -+++ b/include/boost/atomic/detail/cas128strong.hpp -@@ -196,15 +196,17 @@ class base_atomic<T, void, 16, Sign> - - public: - BOOST_DEFAULTED_FUNCTION(base_atomic(void), {}) -- explicit base_atomic(value_type const& v) BOOST_NOEXCEPT : v_(0) -+ explicit base_atomic(value_type const& v) BOOST_NOEXCEPT - { -+ memset(&v_, 0, sizeof(v_)); - memcpy(&v_, &v, sizeof(value_type)); - } - - void - store(value_type const& value, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT - { -- storage_type value_s = 0; -+ storage_type value_s; -+ memset(&value_s, 0, sizeof(value_s)); - memcpy(&value_s, &value, sizeof(value_type)); - platform_fence_before_store(order); - platform_store128(value_s, &v_); -@@ -247,7 +249,9 @@ class base_atomic<T, void, 16, Sign> - memory_order success_order, - memory_order failure_order) volatile BOOST_NOEXCEPT - { -- storage_type expected_s = 0, desired_s = 0; -+ storage_type expected_s, desired_s; -+ memset(&expected_s, 0, sizeof(expected_s)); -+ memset(&desired_s, 0, sizeof(desired_s)); - memcpy(&expected_s, &expected, sizeof(value_type)); - memcpy(&desired_s, &desired, sizeof(value_type)); - diff --git a/depends/patches/boost/darwin_boost_atomic-2.patch b/depends/patches/boost/darwin_boost_atomic-2.patch deleted file mode 100644 index ca50765200..0000000000 --- a/depends/patches/boost/darwin_boost_atomic-2.patch +++ /dev/null @@ -1,55 +0,0 @@ -diff --git a/include/boost/atomic/detail/gcc-atomic.hpp b/include/boost/atomic/detail/gcc-atomic.hpp -index a130590..4af99a1 100644 ---- a/include/boost/atomic/detail/gcc-atomic.hpp -+++ b/include/boost/atomic/detail/gcc-atomic.hpp -@@ -958,14 +958,16 @@ class base_atomic<T, void, 16, Sign> - - public: - BOOST_DEFAULTED_FUNCTION(base_atomic(void), {}) -- explicit base_atomic(value_type const& v) BOOST_NOEXCEPT : v_(0) -+ explicit base_atomic(value_type const& v) BOOST_NOEXCEPT - { -+ memset(&v_, 0, sizeof(v_)); - memcpy(&v_, &v, sizeof(value_type)); - } - - void store(value_type const& v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT - { -- storage_type tmp = 0; -+ storage_type tmp; -+ memset(&tmp, 0, sizeof(tmp)); - memcpy(&tmp, &v, sizeof(value_type)); - __atomic_store_n(&v_, tmp, atomics::detail::convert_memory_order_to_gcc(order)); - } -@@ -980,7 +982,8 @@ class base_atomic<T, void, 16, Sign> - - value_type exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT - { -- storage_type tmp = 0; -+ storage_type tmp; -+ memset(&tmp, 0, sizeof(tmp)); - memcpy(&tmp, &v, sizeof(value_type)); - tmp = __atomic_exchange_n(&v_, tmp, atomics::detail::convert_memory_order_to_gcc(order)); - value_type res; -@@ -994,7 +997,9 @@ class base_atomic<T, void, 16, Sign> - memory_order success_order, - memory_order failure_order) volatile BOOST_NOEXCEPT - { -- storage_type expected_s = 0, desired_s = 0; -+ storage_type expected_s, desired_s; -+ memset(&expected_s, 0, sizeof(expected_s)); -+ memset(&desired_s, 0, sizeof(desired_s)); - memcpy(&expected_s, &expected, sizeof(value_type)); - memcpy(&desired_s, &desired, sizeof(value_type)); - const bool success = __atomic_compare_exchange_n(&v_, &expected_s, desired_s, false, -@@ -1010,7 +1015,9 @@ class base_atomic<T, void, 16, Sign> - memory_order success_order, - memory_order failure_order) volatile BOOST_NOEXCEPT - { -- storage_type expected_s = 0, desired_s = 0; -+ storage_type expected_s, desired_s; -+ memset(&expected_s, 0, sizeof(expected_s)); -+ memset(&desired_s, 0, sizeof(desired_s)); - memcpy(&expected_s, &expected, sizeof(value_type)); - memcpy(&desired_s, &desired, sizeof(value_type)); - const bool success = __atomic_compare_exchange_n(&v_, &expected_s, desired_s, true, diff --git a/depends/patches/boost/gcc_5_no_cxx11.patch b/depends/patches/boost/gcc_5_no_cxx11.patch deleted file mode 100644 index 04514c593a..0000000000 --- a/depends/patches/boost/gcc_5_no_cxx11.patch +++ /dev/null @@ -1,37 +0,0 @@ -From eec808554936ae068b23df07ab54d4dc6302a695 Mon Sep 17 00:00:00 2001 -From: jzmaddock <jzmaddock@gmail.com> -Date: Sat, 23 Aug 2014 09:38:02 +0100 -Subject: [PATCH] Fix BOOST_NO_CXX11_VARIADIC_TEMPLATES definition - the - feature was introduced in GCC 4.4. - ---- - include/boost/config/compiler/gcc.hpp | 9 +-------- - 1 file changed, 1 insertion(+), 8 deletions(-) - -diff --git a/include/boost/config/compiler/gcc.hpp b/include/boost/config/compiler/gcc.hpp -index f37159d..97d8a18 100644 ---- a/include/boost/config/compiler/gcc.hpp -+++ b/include/boost/config/compiler/gcc.hpp -@@ -154,14 +154,6 @@ - # define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS - # define BOOST_NO_CXX11_RVALUE_REFERENCES - # define BOOST_NO_CXX11_STATIC_ASSERT -- --// Variadic templates compiler: --// http://www.generic-programming.org/~dgregor/cpp/variadic-templates.html --# if defined(__VARIADIC_TEMPLATES) || (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4) && defined(__GXX_EXPERIMENTAL_CXX0X__)) --# define BOOST_HAS_VARIADIC_TMPL --# else --# define BOOST_NO_CXX11_VARIADIC_TEMPLATES --# endif - #endif - - // C++0x features in 4.4.n and later -@@ -176,6 +168,7 @@ - # define BOOST_NO_CXX11_DELETED_FUNCTIONS - # define BOOST_NO_CXX11_TRAILING_RESULT_TYPES - # define BOOST_NO_CXX11_INLINE_NAMESPACES -+# define BOOST_NO_CXX11_VARIADIC_TEMPLATES - #endif - - #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) diff --git a/doc/README.md b/doc/README.md index c0f9ee5220..cf475ef18e 100644 --- a/doc/README.md +++ b/doc/README.md @@ -49,7 +49,7 @@ The following are developer notes on how to build Bitcoin on your native platfor Development --------------------- -The Bitcoin repo's [root README](https://github.com/bitcoin/bitcoin/blob/master/README.md) contains relevant information on the development process and automated testing. +The Bitcoin repo's [root README](/README.md) contains relevant information on the development process and automated testing. - [Developer Notes](developer-notes.md) - [Multiwallet Qt Development](multiwallet-qt.md) diff --git a/doc/bips.md b/doc/bips.md index e73add0130..b8efabbcf2 100644 --- a/doc/bips.md +++ b/doc/bips.md @@ -17,6 +17,7 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.12.0**): * [`BIP 65`](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki): The CHECKLOCKTIMEVERIFY softfork was merged in **v0.12.0** ([PR #6351](https://github.com/bitcoin/bitcoin/pull/6351)), and backported to **v0.11.2** and **v0.10.4**. Mempool-only CLTV was added in [PR #6124](https://github.com/bitcoin/bitcoin/pull/6124). * [`BIP 66`](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki): The strict DER rules and associated version 3 blocks have been implemented since **v0.10.0** ([PR #5713](https://github.com/bitcoin/bitcoin/pull/5713)). * [`BIP 70`](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki) [`71`](https://github.com/bitcoin/bips/blob/master/bip-0071.mediawiki) [`72`](https://github.com/bitcoin/bips/blob/master/bip-0072.mediawiki): Payment Protocol support has been available in Bitcoin Core GUI since **v0.9.0** ([PR #5216](https://github.com/bitcoin/bitcoin/pull/5216)). -* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, but only enforced for peer versions `>=70011` as of **v0.12.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579)). +* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, and enforced for all peer versions as of **v0.13.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579) and [PR #6641](https://github.com/bitcoin/bitcoin/pull/6641)). * [`BIP 125`](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki): Opt-in full replace-by-fee signaling honoured in mempool and mining as of **v0.12.0** ([PR 6871](https://github.com/bitcoin/bitcoin/pull/6871)). * [`BIP 130`](https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki): direct headers announcement is negotiated with peer versions `>=70012` as of **v0.12.0** ([PR 6494](https://github.com/bitcoin/bitcoin/pull/6494)). +* [`BIP 133`](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki): feefilter messages are respected and sent for peer versions `>=70013` as of **v0.13.0** ([PR 7542](https://github.com/bitcoin/bitcoin/pull/7542)). diff --git a/doc/build-unix.md b/doc/build-unix.md index 1d8395162b..5b519b8044 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -11,7 +11,7 @@ for example, when specifying the path of the dependency: ../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX -Here BDB_PREFIX must absolute path - it is defined using $(pwd) which ensures +Here BDB_PREFIX must be an absolute path - it is defined using $(pwd) which ensures the usage of the absolute path. To Build @@ -67,15 +67,17 @@ Build requirements: sudo apt-get install build-essential libtool autotools-dev automake pkg-config libssl-dev libevent-dev bsdmainutils -On at least Ubuntu 14.04+ and Debian 7+ there are generic names for the +Options when installing required Boost library files: + +1. On at least Ubuntu 14.04+ and Debian 7+ there are generic names for the individual boost development packages, so the following can be used to only install necessary parts of boost: - sudo apt-get install libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev + sudo apt-get install libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev -If that doesn't work, you can install all boost development packages with: +2. If that doesn't work, you can install all boost development packages with: - sudo apt-get install libboost-all-dev + sudo apt-get install libboost-all-dev BerkeleyDB is required for the wallet. db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin). You can add the repository and install using the following commands: diff --git a/doc/gitian-building.md b/doc/gitian-building.md index 5ca91505e7..54993d13a9 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -252,7 +252,7 @@ First we need to log in as `root` to set up dependencies and make sure that our user can use the sudo command. Type/paste the following in the terminal: ```bash -apt-get install git ruby sudo apt-cacher-ng qemu-utils debootstrap lxc python-cheetah parted kpartx bridge-utils make ubuntu-archive-keyring +apt-get install git ruby sudo apt-cacher-ng qemu-utils debootstrap lxc python-cheetah parted kpartx bridge-utils make ubuntu-archive-keyring curl adduser debian sudo ``` @@ -262,6 +262,7 @@ Then set up LXC and the rest with the following, which is a complex jumble of se # the version of lxc-start in Debian needs to run as root, so make sure # that the build script can execute it without providing a password echo "%sudo ALL=NOPASSWD: /usr/bin/lxc-start" > /etc/sudoers.d/gitian-lxc +echo "%sudo ALL=NOPASSWD: /usr/bin/lxc-execute" >> /etc/sudoers.d/gitian-lxc # make /etc/rc.local script that sets up bridge between guest and host echo '#!/bin/sh -e' > /etc/rc.local echo 'brctl addbr br0' >> /etc/rc.local diff --git a/doc/release-notes.md b/doc/release-notes.md index 707f2357f8..806d174ebf 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -51,6 +51,17 @@ The following outputs are affected by this change: ### P2P protocol and network code +The p2p alert system has been removed in #7692 and the 'alert' message is no longer supported. + + +Fee filtering of invs (BIP 133) +------------------------------------ + +The optional new p2p message "feefilter" is implemented and the protocol +version is bumped to 70013. Upon receiving a feefilter message from a peer, +a node will not send invs for any transactions which do not meet the filter +feerate. [BIP 133](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki) + ### Validation ### Build system diff --git a/doc/release-notes/release-notes-0.12.0.md b/doc/release-notes/release-notes-0.12.0.md index b586d754f0..135cd68a7c 100644 --- a/doc/release-notes/release-notes-0.12.0.md +++ b/doc/release-notes/release-notes-0.12.0.md @@ -99,7 +99,7 @@ Direct headers announcement (BIP 130) Between compatible peers, [BIP 130] (https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki) -direct headers announcement is used. This means that blocks are advertized by +direct headers announcement is used. This means that blocks are advertised by announcing their headers directly, instead of just announcing the hash. In a reorganization, all new headers are sent, instead of just the new tip. This can often prevent an extra roundtrip before the actual block is downloaded. @@ -272,7 +272,7 @@ at all. Therefore, a fallback value can be set with `-fallbackfee=<f>` At all times, Bitcoin Core will cap fees at `-maxtxfee=<x>` (default: 0.10) BTC. -Furthermore, Bitcoin Core will never create transactions smaller than +Furthermore, Bitcoin Core will never create transactions paying less than the current minimum relay fee. Finally, a user can set the minimum fee rate for all transactions with `-mintxfee=<i>`, which defaults to 1000 satoshis per kB. @@ -701,7 +701,7 @@ git merge commit are mentioned. - #7112 `96b8025` reduce cs_main locks during tip update, more fluently update UI (Jonas Schnelli) - #7206 `f43c2f9` Add "NODE_BLOOM" to guiutil so that peers don't get UNKNOWN[4] (Matt Corallo) - #7282 `5cadf3e` fix coincontrol update issue when deleting a send coins entry (Jonas Schnelli) -- #7319 `1320300` Intro: Display required space (Jonas Schnelli) +- #7319 `1320300` Intro: Display required space (MarcoFalke) - #7318 `9265e89` quickfix for RPC timer interface problem (Jonas Schnelli) - #7327 `b16b5bc` [Wallet] Transaction View: LastMonth calculation fixed (crowning-) - #7364 `7726c48` [qt] Windows: Make rpcconsole monospace font larger (MarcoFalke) @@ -809,6 +809,7 @@ Thanks to everyone who directly contributed to this release: - Chris Kleeschulte - Christian Decker - Cory Fields +- crowning- - daniel - Daniel Cousens - Daniel Kraft @@ -841,7 +842,6 @@ Thanks to everyone who directly contributed to this release: - Kevin Cooper - lpescher - Luke Dashjr -- Marco - MarcoFalke - Mark Friedenbach - Matt diff --git a/doc/release-process.md b/doc/release-process.md index 8fb083d0d4..2c83896c22 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -210,7 +210,7 @@ Note: check that SHA256SUMS itself doesn't end up in SHA256SUMS, which is a spur - Optionally reddit /r/Bitcoin, ... but this will usually sort out itself -- Notify BlueMatt so that he can start building [https://launchpad.net/~bitcoin/+archive/ubuntu/bitcoin](the PPAs) +- Notify BlueMatt so that he can start building [the PPAs](https://launchpad.net/~bitcoin/+archive/ubuntu/bitcoin) - Add release notes for the new version to the directory `doc/release-notes` in git master diff --git a/qa/README.md b/qa/README.md index 758d1f47e5..2b476c4d8d 100644 --- a/qa/README.md +++ b/qa/README.md @@ -5,6 +5,17 @@ Every pull request to the bitcoin repository is built and run through the regression test suite. You can also run all or only individual tests locally. +Test dependencies +================= +Before running the tests, the following must be installed. + +Unix +---- +The python-zmq library is required. On Ubuntu or Debian it can be installed via: +``` +sudo apt-get install python-zmq +``` + Running tests ============= diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index 7649c1183b..74be96da74 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -40,6 +40,15 @@ if not vars().has_key('ENABLE_UTILS'): ENABLE_UTILS=0 if not vars().has_key('ENABLE_ZMQ'): ENABLE_ZMQ=0 + +# python-zmq may not be installed. Handle this gracefully and with some helpful info +if ENABLE_ZMQ: + try: + import zmq + except ImportError: + print("WARNING: \"import zmq\" failed. Setting ENABLE_ZMQ=0. " \ + "To run zmq tests, see dependency info in /qa/README.md.") + ENABLE_ZMQ=0 ENABLE_COVERAGE=0 @@ -106,6 +115,7 @@ testScripts = [ 'invalidblockrequest.py', 'invalidtxrequest.py', 'abandonconflict.py', + 'p2p-versionbits-warning.py', ] testScriptsExt = [ 'bip65-cltv.py', @@ -117,7 +127,6 @@ testScriptsExt = [ 'getblocktemplate_proposals.py', 'txn_doublespend.py', 'txn_clone.py --mineblock', - 'pruning.py', 'forknotify.py', 'invalidateblock.py', # 'rpcbind_test.py', #temporary, bug in libevent, see #6655 @@ -127,6 +136,8 @@ testScriptsExt = [ 'mempool_packages.py', 'maxuploadtarget.py', 'replace-by-fee.py', + 'p2p-feefilter.py', + 'pruning.py', # leave pruning last as it takes a REALLY long time ] #Enable ZMQ tests diff --git a/qa/rpc-tests/abandonconflict.py b/qa/rpc-tests/abandonconflict.py index 38028df079..a83aa97fcd 100755 --- a/qa/rpc-tests/abandonconflict.py +++ b/qa/rpc-tests/abandonconflict.py @@ -83,6 +83,12 @@ class AbandonConflictTest(BitcoinTestFramework): # inputs are still spent, but change not received newbalance = self.nodes[0].getbalance() assert(newbalance == balance - Decimal("24.9996")) + # Unconfirmed received funds that are not in mempool, also shouldn't show + # up in unconfirmed balance + unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance() + assert(unconfbalance == newbalance) + # Also shouldn't show up in listunspent + assert(not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)]) balance = newbalance # Abandon original transaction and verify inputs are available again diff --git a/qa/rpc-tests/bip68-sequence.py b/qa/rpc-tests/bip68-sequence.py index bd61282fa1..84f941da33 100755 --- a/qa/rpc-tests/bip68-sequence.py +++ b/qa/rpc-tests/bip68-sequence.py @@ -13,7 +13,6 @@ from test_framework.script import * from test_framework.mininode import * from test_framework.blocktools import * -COIN = 100000000 SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31) SEQUENCE_LOCKTIME_TYPE_FLAG = (1<<22) # this means use time (0 means height) SEQUENCE_LOCKTIME_GRANULARITY = 9 # this is a bit-shift diff --git a/qa/rpc-tests/blockchain.py b/qa/rpc-tests/blockchain.py index 7045ae435c..272a5dc154 100755 --- a/qa/rpc-tests/blockchain.py +++ b/qa/rpc-tests/blockchain.py @@ -28,6 +28,7 @@ class BlockchainTest(BitcoinTestFramework): Test blockchain-related RPC calls: - gettxoutsetinfo + - verifychain """ @@ -44,6 +45,7 @@ class BlockchainTest(BitcoinTestFramework): def run_test(self): self._test_gettxoutsetinfo() self._test_getblockheader() + self.nodes[0].verifychain(4, 0) def _test_gettxoutsetinfo(self): node = self.nodes[0] diff --git a/qa/rpc-tests/disablewallet.py b/qa/rpc-tests/disablewallet.py index 6964348d55..5af8158467 100755 --- a/qa/rpc-tests/disablewallet.py +++ b/qa/rpc-tests/disablewallet.py @@ -29,5 +29,19 @@ class DisableWalletTest (BitcoinTestFramework): x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') assert(x['isvalid'] == True) + # Checking mining to an address without a wallet + try: + self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') + except JSONRPCException,e: + assert("Invalid address" not in e.error['message']) + assert("ProcessNewBlock, block not accepted" not in e.error['message']) + assert("Couldn't create new block" not in e.error['message']) + + try: + self.nodes[0].generatetoaddress(1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') + raise AssertionError("Must not mine to invalid address!") + except JSONRPCException,e: + assert("Invalid address" in e.error['message']) + if __name__ == '__main__': DisableWalletTest ().main () diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py index 0287965b97..4458712815 100755 --- a/qa/rpc-tests/fundrawtransaction.py +++ b/qa/rpc-tests/fundrawtransaction.py @@ -71,7 +71,7 @@ class RawTransactionsTest(BitcoinTestFramework): rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) - assert_equal(len(dec_tx['vin']) > 0, True) #test if we have enought inputs + assert(len(dec_tx['vin']) > 0) #test if we have enought inputs ############################## # simple test with two coins # @@ -84,7 +84,7 @@ class RawTransactionsTest(BitcoinTestFramework): rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) - assert_equal(len(dec_tx['vin']) > 0, True) #test if we have enough inputs + assert(len(dec_tx['vin']) > 0) #test if we have enough inputs ############################## # simple test with two coins # @@ -97,7 +97,7 @@ class RawTransactionsTest(BitcoinTestFramework): rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) - assert_equal(len(dec_tx['vin']) > 0, True) + assert(len(dec_tx['vin']) > 0) assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') @@ -116,7 +116,7 @@ class RawTransactionsTest(BitcoinTestFramework): for out in dec_tx['vout']: totalOut += out['value'] - assert_equal(len(dec_tx['vin']) > 0, True) + assert(len(dec_tx['vin']) > 0) assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') @@ -130,7 +130,7 @@ class RawTransactionsTest(BitcoinTestFramework): utx = aUtx break - assert_equal(utx!=False, True) + assert(utx!=False) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] outputs = { self.nodes[0].getnewaddress() : 1.0 } @@ -159,7 +159,7 @@ class RawTransactionsTest(BitcoinTestFramework): utx = aUtx break - assert_equal(utx!=False, True) + assert(utx!=False) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] outputs = { self.nodes[0].getnewaddress() : Decimal(5.0) - fee - feeTolerance } @@ -189,7 +189,7 @@ class RawTransactionsTest(BitcoinTestFramework): utx = aUtx break - assert_equal(utx!=False, True) + assert(utx!=False) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] outputs = { self.nodes[0].getnewaddress() : 1.0 } @@ -234,7 +234,7 @@ class RawTransactionsTest(BitcoinTestFramework): utx2 = aUtx - assert_equal(utx!=False, True) + assert(utx!=False) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ] outputs = { self.nodes[0].getnewaddress() : 6.0 } @@ -276,7 +276,7 @@ class RawTransactionsTest(BitcoinTestFramework): utx2 = aUtx - assert_equal(utx!=False, True) + assert(utx!=False) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ] outputs = { self.nodes[0].getnewaddress() : 6.0, self.nodes[0].getnewaddress() : 1.0 } @@ -306,14 +306,11 @@ class RawTransactionsTest(BitcoinTestFramework): rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) - errorString = "" try: rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + raise AssertionError("Spent more than available") except JSONRPCException,e: - errorString = e.error['message'] - - assert("Insufficient" in errorString) - + assert("Insufficient" in e.error['message']) ############################################################ @@ -462,12 +459,11 @@ class RawTransactionsTest(BitcoinTestFramework): self.is_network_split=False self.sync_all() - error = False try: self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2) - except: - error = True - assert(error) + raise AssertionError("Wallet unlocked without passphrase") + except JSONRPCException as e: + assert('walletpassphrase' in e.error['message']) oldBalance = self.nodes[0].getbalance() @@ -580,7 +576,7 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal(len(res_dec["vin"]), 1) assert_equal(res_dec["vin"][0]["txid"], watchonly_txid) - assert_equal("fee" in result.keys(), True) + assert("fee" in result.keys()) assert_greater_than(result["changepos"], -1) ############################################################### diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py index f83b5f140d..d2cb4ab8d6 100755 --- a/qa/rpc-tests/getblocktemplate_proposals.py +++ b/qa/rpc-tests/getblocktemplate_proposals.py @@ -120,10 +120,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework): # Test 3: Truncated final tx lastbyte = txlist[-1].pop() - try: - assert_template(node, tmpl, txlist, 'n/a') - except JSONRPCException: - pass # Expected + assert_raises(JSONRPCException, assert_template, node, tmpl, txlist, 'n/a') txlist[-1].append(lastbyte) # Test 4: Add an invalid tx to the end (duplicate of gen tx) @@ -144,10 +141,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework): # Test 7: Bad tx count txlist.append(b'') - try: - assert_template(node, tmpl, txlist, 'n/a') - except JSONRPCException: - pass # Expected + assert_raises(JSONRPCException, assert_template, node, tmpl, txlist, 'n/a') txlist.pop() # Test 8: Bad bits diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py index eb548aee9d..c231676ec8 100755 --- a/qa/rpc-tests/httpbasics.py +++ b/qa/rpc-tests/httpbasics.py @@ -37,14 +37,14 @@ class HTTPBasicsTest (BitcoinTestFramework): conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() - assert_equal('"error":null' in out1, True) - assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! + assert('"error":null' in out1) + assert(conn.sock!=None) #according to http/1.1 connection must still be open! #send 2nd request without closing connection conn.request('POST', '/', '{"method": "getchaintips"}', headers) out2 = conn.getresponse().read() - assert_equal('"error":null' in out1, True) #must also response with a correct json-rpc message - assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! + assert('"error":null' in out1) #must also response with a correct json-rpc message + assert(conn.sock!=None) #according to http/1.1 connection must still be open! conn.close() #same should be if we add keep-alive because this should be the std. behaviour @@ -54,14 +54,14 @@ class HTTPBasicsTest (BitcoinTestFramework): conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() - assert_equal('"error":null' in out1, True) - assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! + assert('"error":null' in out1) + assert(conn.sock!=None) #according to http/1.1 connection must still be open! #send 2nd request without closing connection conn.request('POST', '/', '{"method": "getchaintips"}', headers) out2 = conn.getresponse().read() - assert_equal('"error":null' in out1, True) #must also response with a correct json-rpc message - assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! + assert('"error":null' in out1) #must also response with a correct json-rpc message + assert(conn.sock!=None) #according to http/1.1 connection must still be open! conn.close() #now do the same with "Connection: close" @@ -71,8 +71,8 @@ class HTTPBasicsTest (BitcoinTestFramework): conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() - assert_equal('"error":null' in out1, True) - assert_equal(conn.sock!=None, False) #now the connection must be closed after the response + assert('"error":null' in out1) + assert(conn.sock==None) #now the connection must be closed after the response #node1 (2nd node) is running with disabled keep-alive option urlNode1 = urlparse.urlparse(self.nodes[1].url) @@ -83,7 +83,7 @@ class HTTPBasicsTest (BitcoinTestFramework): conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() - assert_equal('"error":null' in out1, True) + assert('"error":null' in out1) #node2 (third node) is running with standard keep-alive parameters which means keep-alive is on urlNode2 = urlparse.urlparse(self.nodes[2].url) @@ -94,8 +94,8 @@ class HTTPBasicsTest (BitcoinTestFramework): conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() - assert_equal('"error":null' in out1, True) - assert_equal(conn.sock!=None, True) #connection must be closed because bitcoind should use keep-alive by default + assert('"error":null' in out1) + assert(conn.sock!=None) #connection must be closed because bitcoind should use keep-alive by default # Check excessive request size conn = httplib.HTTPConnection(urlNode2.hostname, urlNode2.port) diff --git a/qa/rpc-tests/invalidblockrequest.py b/qa/rpc-tests/invalidblockrequest.py index f91a8da015..daad312d36 100755 --- a/qa/rpc-tests/invalidblockrequest.py +++ b/qa/rpc-tests/invalidblockrequest.py @@ -78,8 +78,8 @@ class InvalidBlockRequestTest(ComparisonTestFramework): self.block_time += 1 # chr(81) is OP_TRUE - tx1 = create_transaction(self.block1.vtx[0], 0, chr(81), 50*100000000) - tx2 = create_transaction(tx1, 0, chr(81), 50*100000000) + tx1 = create_transaction(self.block1.vtx[0], 0, chr(81), 50 * COIN) + tx2 = create_transaction(tx1, 0, chr(81), 50 * COIN) block2.vtx.extend([tx1, tx2]) block2.hashMerkleRoot = block2.calc_merkle_root() @@ -103,7 +103,7 @@ class InvalidBlockRequestTest(ComparisonTestFramework): ''' block3 = create_block(self.tip, create_coinbase(height), self.block_time) self.block_time += 1 - block3.vtx[0].vout[0].nValue = 100*100000000 # Too high! + block3.vtx[0].vout[0].nValue = 100 * COIN # Too high! block3.vtx[0].sha256=None block3.vtx[0].calc_sha256() block3.hashMerkleRoot = block3.calc_merkle_root() diff --git a/qa/rpc-tests/invalidtxrequest.py b/qa/rpc-tests/invalidtxrequest.py index c2fe4f1dff..8fe471ccd3 100755 --- a/qa/rpc-tests/invalidtxrequest.py +++ b/qa/rpc-tests/invalidtxrequest.py @@ -63,7 +63,7 @@ class InvalidTxRequestTest(ComparisonTestFramework): # chr(100) is OP_NOTIF # Transaction will be rejected with code 16 (REJECT_INVALID) - tx1 = create_transaction(self.block1.vtx[0], 0, chr(100), 50*100000000 - 12000) + tx1 = create_transaction(self.block1.vtx[0], 0, chr(100), 50 * COIN - 12000) yield TestInstance([[tx1, RejectResult(16, 'mandatory-script-verify-flag-failed')]]) # TODO: test further transactions... diff --git a/qa/rpc-tests/listtransactions.py b/qa/rpc-tests/listtransactions.py index 45ede8f040..da1e98dc33 100755 --- a/qa/rpc-tests/listtransactions.py +++ b/qa/rpc-tests/listtransactions.py @@ -7,7 +7,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -from test_framework.mininode import CTransaction +from test_framework.mininode import CTransaction, COIN import cStringIO import binascii @@ -192,7 +192,7 @@ class ListTransactionsTest(BitcoinTestFramework): # Replace tx3, and check that tx4 becomes unknown tx3_b = tx3_modified - tx3_b.vout[0].nValue -= 0.004*100000000 # bump the fee + tx3_b.vout[0].nValue -= 0.004 * COIN # bump the fee tx3_b = binascii.hexlify(tx3_b.serialize()).decode('utf-8') tx3_b_signed = self.nodes[0].signrawtransaction(tx3_b)['hex'] txid_3b = self.nodes[0].sendrawtransaction(tx3_b_signed, True) diff --git a/qa/rpc-tests/maxuploadtarget.py b/qa/rpc-tests/maxuploadtarget.py index 4d6b343f77..e4127500cd 100755 --- a/qa/rpc-tests/maxuploadtarget.py +++ b/qa/rpc-tests/maxuploadtarget.py @@ -7,7 +7,6 @@ from test_framework.mininode import * from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -from test_framework.comptool import wait_until import time ''' @@ -176,7 +175,7 @@ class MaxUploadTest(BitcoinTestFramework): getdata_request.inv.append(CInv(2, big_old_block)) max_bytes_per_day = 200*1024*1024 - daily_buffer = 144 * 1000000 + daily_buffer = 144 * MAX_BLOCK_SIZE max_bytes_available = max_bytes_per_day - daily_buffer success_count = max_bytes_available / old_block_size diff --git a/qa/rpc-tests/mempool_limit.py b/qa/rpc-tests/mempool_limit.py index 7914ceea22..c19a63c699 100755 --- a/qa/rpc-tests/mempool_limit.py +++ b/qa/rpc-tests/mempool_limit.py @@ -38,7 +38,6 @@ class MempoolLimitTest(BitcoinTestFramework): self.nodes[0].settxfee(0) # return to automatic fee selection txFS = self.nodes[0].signrawtransaction(txF['hex']) txid = self.nodes[0].sendrawtransaction(txFS['hex']) - self.nodes[0].lockunspent(True, [us0]) relayfee = self.nodes[0].getnetworkinfo()['relayfee'] base_fee = relayfee*100 diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py index 47c1028b9f..bc3f9e051c 100755 --- a/qa/rpc-tests/mempool_packages.py +++ b/qa/rpc-tests/mempool_packages.py @@ -7,6 +7,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * +from test_framework.mininode import COIN MAX_ANCESTORS = 25 MAX_DESCENDANTS = 25 @@ -59,13 +60,12 @@ class MempoolPackagesTest(BitcoinTestFramework): descendant_count = 1 descendant_fees = 0 descendant_size = 0 - SATOSHIS = 100000000 for x in reversed(chain): assert_equal(mempool[x]['descendantcount'], descendant_count) descendant_fees += mempool[x]['fee'] assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee']) - assert_equal(mempool[x]['descendantfees'], SATOSHIS*descendant_fees) + assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN) descendant_size += mempool[x]['size'] assert_equal(mempool[x]['descendantsize'], descendant_size) descendant_count += 1 @@ -78,7 +78,7 @@ class MempoolPackagesTest(BitcoinTestFramework): descendant_fees = 0 for x in reversed(chain): descendant_fees += mempool[x]['fee'] - assert_equal(mempool[x]['descendantfees'], SATOSHIS*descendant_fees+1000) + assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 1000) # Adding one more transaction on to the chain should fail. try: @@ -106,7 +106,7 @@ class MempoolPackagesTest(BitcoinTestFramework): descendant_fees += mempool[x]['fee'] if (x == chain[-1]): assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee']+satoshi_round(0.00002)) - assert_equal(mempool[x]['descendantfees'], SATOSHIS*descendant_fees+2000) + assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 2000) # TODO: check that node1's mempool is as expected diff --git a/qa/rpc-tests/mempool_reorg.py b/qa/rpc-tests/mempool_reorg.py index 40684e7fbb..5e9856e5d4 100755 --- a/qa/rpc-tests/mempool_reorg.py +++ b/qa/rpc-tests/mempool_reorg.py @@ -25,14 +25,6 @@ class MempoolCoinbaseTest(BitcoinTestFramework): self.is_network_split = False self.sync_all() - def create_tx(self, from_txid, to_address, amount): - inputs = [{ "txid" : from_txid, "vout" : 0}] - outputs = { to_address : amount } - rawtx = self.nodes[0].createrawtransaction(inputs, outputs) - signresult = self.nodes[0].signrawtransaction(rawtx) - assert_equal(signresult["complete"], True) - return signresult["hex"] - def run_test(self): start_count = self.nodes[0].getblockcount() @@ -52,9 +44,9 @@ class MempoolCoinbaseTest(BitcoinTestFramework): # and make sure the mempool code behaves correctly. b = [ self.nodes[0].getblockhash(n) for n in range(101, 105) ] coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ] - spend_101_raw = self.create_tx(coinbase_txids[1], node1_address, 49.99) - spend_102_raw = self.create_tx(coinbase_txids[2], node0_address, 49.99) - spend_103_raw = self.create_tx(coinbase_txids[3], node0_address, 49.99) + spend_101_raw = create_tx(self.nodes[0], coinbase_txids[1], node1_address, 49.99) + spend_102_raw = create_tx(self.nodes[0], coinbase_txids[2], node0_address, 49.99) + spend_103_raw = create_tx(self.nodes[0], coinbase_txids[3], node0_address, 49.99) # Create a block-height-locked transaction which will be invalid after reorg timelock_tx = self.nodes[0].createrawtransaction([{"txid": coinbase_txids[0], "vout": 0}], {node0_address: 49.99}) @@ -71,8 +63,8 @@ class MempoolCoinbaseTest(BitcoinTestFramework): assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx) # Create 102_1 and 103_1: - spend_102_1_raw = self.create_tx(spend_102_id, node1_address, 49.98) - spend_103_1_raw = self.create_tx(spend_103_id, node1_address, 49.98) + spend_102_1_raw = create_tx(self.nodes[0], spend_102_id, node1_address, 49.98) + spend_103_1_raw = create_tx(self.nodes[0], spend_103_id, node1_address, 49.98) # Broadcast and mine 103_1: spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw) diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py index 9fcc88a2a3..0ba46e6f51 100755 --- a/qa/rpc-tests/mempool_resurrect_test.py +++ b/qa/rpc-tests/mempool_resurrect_test.py @@ -21,14 +21,6 @@ class MempoolCoinbaseTest(BitcoinTestFramework): self.nodes.append(start_node(0, self.options.tmpdir, args)) self.is_network_split = False - def create_tx(self, from_txid, to_address, amount): - inputs = [{ "txid" : from_txid, "vout" : 0}] - outputs = { to_address : amount } - rawtx = self.nodes[0].createrawtransaction(inputs, outputs) - signresult = self.nodes[0].signrawtransaction(rawtx) - assert_equal(signresult["complete"], True) - return signresult["hex"] - def run_test(self): node0_address = self.nodes[0].getnewaddress() # Spend block 1/2/3's coinbase transactions @@ -43,13 +35,13 @@ class MempoolCoinbaseTest(BitcoinTestFramework): b = [ self.nodes[0].getblockhash(n) for n in range(1, 4) ] coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ] - spends1_raw = [ self.create_tx(txid, node0_address, 49.99) for txid in coinbase_txids ] + spends1_raw = [ create_tx(self.nodes[0], txid, node0_address, 49.99) for txid in coinbase_txids ] spends1_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw ] blocks = [] blocks.extend(self.nodes[0].generate(1)) - spends2_raw = [ self.create_tx(txid, node0_address, 49.98) for txid in spends1_id ] + spends2_raw = [ create_tx(self.nodes[0], txid, node0_address, 49.98) for txid in spends1_id ] spends2_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw ] blocks.extend(self.nodes[0].generate(1)) diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py index 16f512db38..507b5ff416 100755 --- a/qa/rpc-tests/mempool_spendcoinbase.py +++ b/qa/rpc-tests/mempool_spendcoinbase.py @@ -26,14 +26,6 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework): self.nodes.append(start_node(0, self.options.tmpdir, args)) self.is_network_split = False - def create_tx(self, from_txid, to_address, amount): - inputs = [{ "txid" : from_txid, "vout" : 0}] - outputs = { to_address : amount } - rawtx = self.nodes[0].createrawtransaction(inputs, outputs) - signresult = self.nodes[0].signrawtransaction(rawtx) - assert_equal(signresult["complete"], True) - return signresult["hex"] - def run_test(self): chain_height = self.nodes[0].getblockcount() assert_equal(chain_height, 200) @@ -44,7 +36,7 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework): # is too immature to spend. b = [ self.nodes[0].getblockhash(n) for n in range(101, 103) ] coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ] - spends_raw = [ self.create_tx(txid, node0_address, 49.99) for txid in coinbase_txids ] + spends_raw = [ create_tx(self.nodes[0], txid, node0_address, 49.99) for txid in coinbase_txids ] spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0]) diff --git a/qa/rpc-tests/multi_rpc.py b/qa/rpc-tests/multi_rpc.py index 62071d426e..2452b77319 100755 --- a/qa/rpc-tests/multi_rpc.py +++ b/qa/rpc-tests/multi_rpc.py @@ -44,7 +44,7 @@ class HTTPBasicsTest (BitcoinTestFramework): #Old authpair authpair = url.username + ':' + url.password - #New authpair generated via contrib/rpcuser tool + #New authpair generated via share/rpcuser tool rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144" password = "cA773lm788buwYe4g4WT+05pKyNruVKjQ25x3n0DQcM=" diff --git a/qa/rpc-tests/p2p-feefilter.py b/qa/rpc-tests/p2p-feefilter.py new file mode 100755 index 0000000000..f85c18dcd5 --- /dev/null +++ b/qa/rpc-tests/p2p-feefilter.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python2 +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from test_framework.mininode import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import time + +''' +FeeFilterTest -- test processing of feefilter messages +''' + +def hashToHex(hash): + return format(hash, '064x').decode('utf-8') + +# Wait up to 60 secs to see if the testnode has received all the expected invs +def allInvsMatch(invsExpected, testnode): + for x in xrange(60): + with mininode_lock: + if (sorted(invsExpected) == sorted(testnode.txinvs)): + return True; + time.sleep(1) + return False; + +# TestNode: bare-bones "peer". Used to track which invs are received from a node +# and to send the node feefilter messages. +class TestNode(SingleNodeConnCB): + def __init__(self): + SingleNodeConnCB.__init__(self) + self.txinvs = [] + + def on_inv(self, conn, message): + for i in message.inv: + if (i.type == 1): + self.txinvs.append(hashToHex(i.hash)) + + def clear_invs(self): + with mininode_lock: + self.txinvs = [] + + def send_filter(self, feerate): + self.send_message(msg_feefilter(feerate)) + self.sync_with_ping() + +class FeeFilterTest(BitcoinTestFramework): + def setup_network(self): + # Node1 will be used to generate txs which should be relayed from Node0 + # to our test node + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros"])) + connect_nodes(self.nodes[0], 1) + + def run_test(self): + node1 = self.nodes[1] + # Get out of IBD + node1.generate(1) + sync_blocks(self.nodes) + + # Setup the p2p connections and start up the network thread. + test_node = TestNode() + connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node) + test_node.add_connection(connection) + NetworkThread().start() + test_node.wait_for_verack() + + # Test that invs are received for all txs at feerate of 20 sat/byte + node1.settxfee(Decimal("0.00020000")) + txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)] + assert(allInvsMatch(txids, test_node)) + test_node.clear_invs() + + # Set a filter of 15 sat/byte + test_node.send_filter(15000) + + # Test that txs are still being received (paying 20 sat/byte) + txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)] + assert(allInvsMatch(txids, test_node)) + test_node.clear_invs() + + # Change tx fee rate to 10 sat/byte and test they are no longer received + node1.settxfee(Decimal("0.00010000")) + [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)] + sync_mempools(self.nodes) # must be sure node 0 has received all txs + time.sleep(10) # wait 10 secs to be sure its doesn't relay any + assert(allInvsMatch([], test_node)) + test_node.clear_invs() + + # Remove fee filter and check that txs are received again + test_node.send_filter(0) + txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)] + assert(allInvsMatch(txids, test_node)) + test_node.clear_invs() + +if __name__ == '__main__': + FeeFilterTest().main() diff --git a/qa/rpc-tests/p2p-versionbits-warning.py b/qa/rpc-tests/p2p-versionbits-warning.py new file mode 100755 index 0000000000..061dcbf0e1 --- /dev/null +++ b/qa/rpc-tests/p2p-versionbits-warning.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python2 +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from test_framework.mininode import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import time +from test_framework.blocktools import create_block, create_coinbase + +''' +Test version bits' warning system. + +Generate chains with block versions that appear to be signalling unknown +soft-forks, and test that warning alerts are generated. +''' + +VB_PERIOD = 144 # versionbits period length for regtest +VB_THRESHOLD = 108 # versionbits activation threshold for regtest +VB_TOP_BITS = 0x20000000 +VB_UNKNOWN_BIT = 27 # Choose a bit unassigned to any deployment + +# TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending +# p2p messages to a node, generating the messages in the main testing logic. +class TestNode(NodeConnCB): + def __init__(self): + NodeConnCB.__init__(self) + self.connection = None + self.ping_counter = 1 + self.last_pong = msg_pong() + + def add_connection(self, conn): + self.connection = conn + + def on_inv(self, conn, message): + pass + + # 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 + + # Sync up with the node after delivery of a block + def sync_with_ping(self, timeout=30): + self.connection.send_message(msg_ping(nonce=self.ping_counter)) + received_pong = False + sleep_time = 0.05 + while not received_pong and timeout > 0: + time.sleep(sleep_time) + timeout -= sleep_time + with mininode_lock: + if self.last_pong.nonce == self.ping_counter: + received_pong = True + self.ping_counter += 1 + return received_pong + + +class VersionBitsWarningTest(BitcoinTestFramework): + def setup_chain(self): + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self): + self.nodes = [] + self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") + # Open and close to create zero-length file + with open(self.alert_filename, 'w') as f: + pass + self.node_options = ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""] + self.nodes.append(start_node(0, self.options.tmpdir, self.node_options)) + + import re + self.vb_pattern = re.compile("^Warning.*versionbit") + + # Send numblocks blocks via peer with nVersionToUse set. + def send_blocks_with_version(self, peer, numblocks, nVersionToUse): + tip = self.nodes[0].getbestblockhash() + height = self.nodes[0].getblockcount() + block_time = self.nodes[0].getblockheader(tip)["time"]+1 + tip = int(tip, 16) + + for i in xrange(numblocks): + block = create_block(tip, create_coinbase(height+1), block_time) + block.nVersion = nVersionToUse + block.solve() + peer.send_message(msg_block(block)) + block_time += 1 + height += 1 + tip = block.sha256 + peer.sync_with_ping() + + def test_versionbits_in_alert_file(self): + with open(self.alert_filename, 'r') as f: + alert_text = f.read() + assert(self.vb_pattern.match(alert_text)) + + def run_test(self): + # Setup the p2p connection and start up the network thread. + test_node = TestNode() + + connections = [] + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node)) + test_node.add_connection(connections[0]) + + NetworkThread().start() # Start up network handling in another thread + + # Test logic begins here + test_node.wait_for_verack() + + # 1. Have the node mine one period worth of blocks + self.nodes[0].generate(VB_PERIOD) + + # 2. Now build one period of blocks on the tip, with < VB_THRESHOLD + # blocks signaling some unknown bit. + nVersion = VB_TOP_BITS | (1<<VB_UNKNOWN_BIT) + self.send_blocks_with_version(test_node, VB_THRESHOLD-1, nVersion) + + # Fill rest of period with regular version blocks + self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD + 1) + # Check that we're not getting any versionbit-related errors in + # getinfo() + assert(not self.vb_pattern.match(self.nodes[0].getinfo()["errors"])) + + # 3. Now build one period of blocks with >= VB_THRESHOLD blocks signaling + # some unknown bit + self.send_blocks_with_version(test_node, VB_THRESHOLD, nVersion) + self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD) + # Might not get a versionbits-related alert yet, as we should + # have gotten a different alert due to more than 51/100 blocks + # being of unexpected version. + # Check that getinfo() shows some kind of error. + assert(len(self.nodes[0].getinfo()["errors"]) != 0) + + # Mine a period worth of expected blocks so the generic block-version warning + # is cleared, and restart the node. This should move the versionbit state + # to ACTIVE. + self.nodes[0].generate(VB_PERIOD) + stop_node(self.nodes[0], 0) + wait_bitcoinds() + # Empty out the alert file + with open(self.alert_filename, 'w') as f: + pass + self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]) + + # Connecting one block should be enough to generate an error. + self.nodes[0].generate(1) + assert(len(self.nodes[0].getinfo()["errors"]) != 0) + stop_node(self.nodes[0], 0) + wait_bitcoinds() + self.test_versionbits_in_alert_file() + + # Test framework expects the node to still be running... + self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]) + + +if __name__ == '__main__': + VersionBitsWarningTest().main() diff --git a/qa/rpc-tests/prioritise_transaction.py b/qa/rpc-tests/prioritise_transaction.py index 4a79d38da0..f8d9063b4e 100755 --- a/qa/rpc-tests/prioritise_transaction.py +++ b/qa/rpc-tests/prioritise_transaction.py @@ -9,8 +9,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * - -COIN = 100000000 +from test_framework.mininode import COIN, MAX_BLOCK_SIZE class PrioritiseTransactionTest(BitcoinTestFramework): @@ -29,14 +28,29 @@ class PrioritiseTransactionTest(BitcoinTestFramework): self.relayfee = self.nodes[0].getnetworkinfo()['relayfee'] def run_test(self): - utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], 90) + utxo_count = 90 + utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], utxo_count) base_fee = self.relayfee*100 # our transactions are smaller than 100kb txids = [] # Create 3 batches of transactions at 3 different fee rate levels + range_size = utxo_count // 3 for i in xrange(3): txids.append([]) - txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[30*i:30*i+30], (i+1)*base_fee) + start_range = i * range_size + end_range = start_range + range_size + txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[start_range:end_range], (i+1)*base_fee) + + # Make sure that the size of each group of transactions exceeds + # MAX_BLOCK_SIZE -- otherwise the test needs to be revised to create + # more transactions. + mempool = self.nodes[0].getrawmempool(True) + sizes = [0, 0, 0] + for i in xrange(3): + for j in txids[i]: + assert(j in mempool) + sizes[i] += mempool[j]['size'] + assert(sizes[i] > MAX_BLOCK_SIZE) # Fail => raise utxo_count # add a fee delta to something in the cheapest bucket and make sure it gets mined # also check that a different entry in the cheapest bucket is NOT mined (lower @@ -47,7 +61,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework): self.nodes[0].generate(1) mempool = self.nodes[0].getrawmempool() - print "Assert that prioritised transasction was mined" + print "Assert that prioritised transaction was mined" assert(txids[0][0] not in mempool) assert(txids[0][1] in mempool) @@ -60,7 +74,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework): assert(high_fee_tx != None) # Add a prioritisation before a tx is in the mempool (de-prioritising a - # high-fee transaction). + # high-fee transaction so that it's now low fee). self.nodes[0].prioritisetransaction(high_fee_tx, -1e15, -int(2*base_fee*COIN)) # Add everything back to mempool @@ -70,8 +84,11 @@ class PrioritiseTransactionTest(BitcoinTestFramework): mempool = self.nodes[0].getrawmempool() assert(high_fee_tx in mempool) - # Now verify the high feerate transaction isn't mined. - self.nodes[0].generate(5) + # Now verify the modified-high feerate transaction isn't mined before + # the other high fee transactions. Keep mining until our mempool has + # decreased by all the high fee size that we calculated above. + while (self.nodes[0].getmempoolinfo()['bytes'] > sizes[0] + sizes[1]): + self.nodes[0].generate(1) # High fee transaction should not have been mined, but other high fee rate # transactions should have been. diff --git a/qa/rpc-tests/replace-by-fee.py b/qa/rpc-tests/replace-by-fee.py index ba1956853a..eded24f405 100755 --- a/qa/rpc-tests/replace-by-fee.py +++ b/qa/rpc-tests/replace-by-fee.py @@ -13,7 +13,6 @@ from test_framework.script import * from test_framework.mininode import * import binascii -COIN = 100000000 MAX_REPLACEMENT_LIMIT = 100 def satoshi_round(amount): diff --git a/qa/rpc-tests/test_framework/blocktools.py b/qa/rpc-tests/test_framework/blocktools.py index 7eea41b75c..b075f69c47 100644 --- a/qa/rpc-tests/test_framework/blocktools.py +++ b/qa/rpc-tests/test_framework/blocktools.py @@ -45,7 +45,7 @@ def create_coinbase(height, pubkey = None): coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff), ser_string(serialize_script_num(height)), 0xffffffff)) coinbaseoutput = CTxOut() - coinbaseoutput.nValue = 50*100000000 + coinbaseoutput.nValue = 50 * COIN halvings = int(height/150) # regtest coinbaseoutput.nValue >>= halvings if (pubkey != None): diff --git a/qa/rpc-tests/test_framework/comptool.py b/qa/rpc-tests/test_framework/comptool.py index a4cd4d0a89..e3f9b43235 100755 --- a/qa/rpc-tests/test_framework/comptool.py +++ b/qa/rpc-tests/test_framework/comptool.py @@ -27,20 +27,6 @@ generator that returns TestInstance objects. See below for definition. global mininode_lock -def wait_until(predicate, attempts=float('inf'), timeout=float('inf')): - attempt = 0 - elapsed = 0 - - while attempt < attempts and elapsed < timeout: - with mininode_lock: - if predicate(): - return True - attempt += 1 - elapsed += 0.05 - time.sleep(0.05) - - return False - class RejectResult(object): ''' Outcome that expects rejection of a transaction or block. diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index 81bb439cea..20386c642c 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -38,6 +38,8 @@ MY_SUBVERSION = "/python-mininode-tester:0.0.1/" MAX_INV_SZ = 50000 MAX_BLOCK_SIZE = 1000000 +COIN = 100000000L # 1 btc in satoshis + # Keep our own socket map for asyncore, so that we can track disconnects # ourselves (to workaround an issue with closing an asyncore socket when # using select) @@ -377,7 +379,7 @@ class CTxOut(object): def __repr__(self): return "CTxOut(nValue=%i.%08i scriptPubKey=%s)" \ - % (self.nValue // 100000000, self.nValue % 100000000, + % (self.nValue // COIN, self.nValue % COIN, binascii.hexlify(self.scriptPubKey)) @@ -426,7 +428,7 @@ class CTransaction(object): def is_valid(self): self.calc_sha256() for tout in self.vout: - if tout.nValue < 0 or tout.nValue > 21000000L * 100000000L: + if tout.nValue < 0 or tout.nValue > 21000000 * COIN: return False return True @@ -1006,6 +1008,37 @@ class msg_reject(object): return "msg_reject: %s %d %s [%064x]" \ % (self.message, self.code, self.reason, self.data) +# Helper function +def wait_until(predicate, attempts=float('inf'), timeout=float('inf')): + attempt = 0 + elapsed = 0 + + while attempt < attempts and elapsed < timeout: + with mininode_lock: + if predicate(): + return True + attempt += 1 + elapsed += 0.05 + time.sleep(0.05) + + return False + +class msg_feefilter(object): + command = "feefilter" + + def __init__(self, feerate=0L): + self.feerate = feerate + + def deserialize(self, f): + self.feerate = struct.unpack("<Q", f.read(8))[0] + + def serialize(self): + r = "" + r += struct.pack("<Q", self.feerate) + return r + + def __repr__(self): + return "msg_feefilter(feerate=%08x)" % self.feerate # This is what a callback should look like for NodeConn # Reimplement the on_* functions to provide handling for events @@ -1082,7 +1115,34 @@ class NodeConnCB(object): def on_close(self, conn): pass def on_mempool(self, conn): pass def on_pong(self, conn, message): pass + def on_feefilter(self, conn, message): pass +# More useful callbacks and functions for NodeConnCB's which have a single NodeConn +class SingleNodeConnCB(NodeConnCB): + def __init__(self): + NodeConnCB.__init__(self) + self.connection = None + self.ping_counter = 1 + self.last_pong = msg_pong() + + def add_connection(self, conn): + self.connection = conn + + # 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 + + # Sync up with the node + def sync_with_ping(self, timeout=30): + def received_pong(): + return (self.last_pong.nonce == self.ping_counter) + self.send_message(msg_ping(nonce=self.ping_counter)) + success = wait_until(received_pong, timeout) + self.ping_counter += 1 + return success # The actual NodeConn class # This class provides an interface for a p2p connection to a specified node @@ -1103,7 +1163,8 @@ class NodeConn(asyncore.dispatcher): "headers": msg_headers, "getheaders": msg_getheaders, "reject": msg_reject, - "mempool": msg_mempool + "mempool": msg_mempool, + "feefilter": msg_feefilter } MAGIC_BYTES = { "mainnet": "\xf9\xbe\xb4\xd9", # mainnet diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 8c472a518d..8d4bd52b94 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -448,6 +448,8 @@ def assert_is_hash_string(string, length=64): def satoshi_round(amount): return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) +# Helper to create at least "count" utxos +# Pass in a fee that is sufficient for relay and mining new transactions. def create_confirmed_utxos(fee, node, count): node.generate(int(0.5*count)+101) utxos = node.listunspent() @@ -475,6 +477,8 @@ def create_confirmed_utxos(fee, node, count): assert(len(utxos) >= count) return utxos +# Create large OP_RETURN txouts that can be appended to a transaction +# to make it large (helper for constructing large transactions). def gen_return_txouts(): # Some pre-processing to create a bunch of OP_RETURN txouts to insert into transactions we create # So we have big transactions (and therefore can't fit very many into each block) @@ -493,6 +497,16 @@ def gen_return_txouts(): txouts = txouts + script_pubkey return txouts +def create_tx(node, coinbase, to_address, amount): + inputs = [{ "txid" : coinbase, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + signresult = node.signrawtransaction(rawtx) + assert_equal(signresult["complete"], True) + return signresult["hex"] + +# Create a spend of each passed-in utxo, splicing in "txouts" to each raw +# transaction to make it large. See gen_return_txouts() above. def create_lots_of_big_transactions(node, txouts, utxos, fee): addr = node.getnewaddress() txids = [] diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 6cd879e4a0..df176601a5 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -59,6 +59,15 @@ class WalletTest (BitcoinTestFramework): self.nodes[0].generate(1) self.sync_all() + # Exercise locking of unspent outputs + unspent_0 = self.nodes[2].listunspent()[0] + unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} + self.nodes[2].lockunspent(False, [unspent_0]) + assert_raises(JSONRPCException, self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) + assert_equal([unspent_0], self.nodes[2].listlockunspent()) + self.nodes[2].lockunspent(True, [unspent_0]) + assert_equal(len(self.nodes[2].listlockunspent()), 0) + # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) self.sync_all() @@ -148,6 +157,10 @@ class WalletTest (BitcoinTestFramework): assert(txid1 in self.nodes[3].getrawmempool()) + # Exercise balance rpcs + assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], 1) + assert_equal(self.nodes[0].getunconfirmedbalance(), 1) + #check if we can list zero value tx as available coins #1. create rawtx #2. hex-changed one output to 0.0 @@ -239,7 +252,7 @@ class WalletTest (BitcoinTestFramework): except JSONRPCException,e: errorString = e.error['message'] - assert_equal("Invalid amount" in errorString, True) + assert("Invalid amount" in errorString) errorString = "" try: @@ -247,11 +260,23 @@ class WalletTest (BitcoinTestFramework): except JSONRPCException,e: errorString = e.error['message'] - assert_equal("not an integer" in errorString, True) + assert("not an integer" in errorString) + + # Mine a block from node0 to an address from node1 + cbAddr = self.nodes[1].getnewaddress() + blkHash = self.nodes[0].generatetoaddress(1, cbAddr)[0] + cbTxId = self.nodes[0].getblock(blkHash)['tx'][0] + self.sync_all() + + # Check that the txid and balance is found by node1 + try: + self.nodes[1].gettransaction(cbTxId) + except JSONRPCException,e: + assert("Invalid or non-wallet transaction id" not in e.error['message']) #check if wallet or blochchain maintenance changes the balance self.sync_all() - self.nodes[0].generate(1) + blocks = self.nodes[0].generate(2) self.sync_all() balance_nodes = [self.nodes[i].getbalance() for i in range(3)] @@ -267,12 +292,14 @@ class WalletTest (BitcoinTestFramework): stop_nodes(self.nodes) wait_bitcoinds() self.nodes = start_nodes(3, self.options.tmpdir, [[m]] * 3) - connect_nodes_bi(self.nodes,0,1) - connect_nodes_bi(self.nodes,1,2) - connect_nodes_bi(self.nodes,0,2) - self.sync_all() assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) + # Exercise listsinceblock with the last two blocks + coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) + assert_equal(coinbase_tx_1["lastblock"], blocks[1]) + assert_equal(len(coinbase_tx_1["transactions"]), 1) + assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) + assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0) if __name__ == '__main__': WalletTest ().main () diff --git a/qa/rpc-tests/zapwallettxes.py b/qa/rpc-tests/zapwallettxes.py index 1ee0f79ac0..1ba4ded249 100755 --- a/qa/rpc-tests/zapwallettxes.py +++ b/qa/rpc-tests/zapwallettxes.py @@ -65,14 +65,8 @@ class ZapWalletTXesTest (BitcoinTestFramework): #restart bitcoind with zapwallettxes self.nodes[0] = start_node(0,self.options.tmpdir, ["-zapwallettxes=1"]) - aException = False - try: - tx3 = self.nodes[0].gettransaction(txid3) - except JSONRPCException,e: - print e - aException = True - - assert_equal(aException, True) #there must be a expection because the unconfirmed wallettx0 must be gone by now + assert_raises(JSONRPCException, self.nodes[0].gettransaction, [txid3]) + #there must be a expection because the unconfirmed wallettx0 must be gone by now tx0 = self.nodes[0].gettransaction(txid0) assert_equal(tx0['txid'], txid0) #tx0 (confirmed) must still be available because it was confirmed diff --git a/share/rpcuser/README.md b/share/rpcuser/README.md index 7c2c909a42..12a8e6fb0c 100644 --- a/share/rpcuser/README.md +++ b/share/rpcuser/README.md @@ -7,5 +7,4 @@ Create an RPC user login credential. Usage: -./rpcuser.py <username> - + ./rpcuser.py <username> diff --git a/src/Makefile.am b/src/Makefile.am index fa7a78f330..6ad7aabae0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -87,7 +87,6 @@ endif # bitcoin core # BITCOIN_CORE_H = \ addrman.h \ - alert.h \ base58.h \ bloom.h \ chain.h \ @@ -152,6 +151,7 @@ BITCOIN_CORE_H = \ utilmoneystr.h \ utiltime.h \ validationinterface.h \ + versionbits.h \ wallet/crypter.h \ wallet/db.h \ wallet/rpcwallet.h \ @@ -175,7 +175,6 @@ libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CP libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_server_a_SOURCES = \ addrman.cpp \ - alert.cpp \ bloom.cpp \ chain.cpp \ checkpoints.cpp \ @@ -204,6 +203,7 @@ libbitcoin_server_a_SOURCES = \ txdb.cpp \ txmempool.cpp \ validationinterface.cpp \ + versionbits.cpp \ $(BITCOIN_CORE_H) if ENABLE_ZMQ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 6ef6a69a2c..4481349e50 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -29,7 +29,7 @@ JSON_TEST_FILES = \ test/data/tx_valid.json \ test/data/sighash.json -RAW_TEST_FILES = test/data/alertTests.raw +RAW_TEST_FILES = GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) @@ -38,6 +38,7 @@ BITCOIN_TESTS =\ test/scriptnum10.h \ test/addrman_tests.cpp \ test/alert_tests.cpp \ + test/amount_tests.cpp \ test/allocator_tests.cpp \ test/base32_tests.cpp \ test/base58_tests.cpp \ @@ -78,9 +79,12 @@ BITCOIN_TESTS =\ test/streams_tests.cpp \ test/test_bitcoin.cpp \ test/test_bitcoin.h \ + test/testutil.cpp \ + test/testutil.h \ test/timedata_tests.cpp \ test/transaction_tests.cpp \ test/txvalidationcache_tests.cpp \ + test/versionbits_tests.cpp \ test/uint256_tests.cpp \ test/univalue_tests.cpp \ test/util_tests.cpp diff --git a/src/alert.cpp b/src/alert.cpp deleted file mode 100644 index eb1cd5e7f6..0000000000 --- a/src/alert.cpp +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2015 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "alert.h" - -#include "clientversion.h" -#include "net.h" -#include "pubkey.h" -#include "timedata.h" -#include "ui_interface.h" -#include "util.h" -#include "utilstrencodings.h" - -#include <stdint.h> -#include <algorithm> -#include <map> - -#include <boost/algorithm/string/classification.hpp> -#include <boost/algorithm/string/replace.hpp> -#include <boost/foreach.hpp> -#include <boost/thread.hpp> - -using namespace std; - -map<uint256, CAlert> mapAlerts; -CCriticalSection cs_mapAlerts; - -void CUnsignedAlert::SetNull() -{ - nVersion = 1; - nRelayUntil = 0; - nExpiration = 0; - nID = 0; - nCancel = 0; - setCancel.clear(); - nMinVer = 0; - nMaxVer = 0; - setSubVer.clear(); - nPriority = 0; - - strComment.clear(); - strStatusBar.clear(); - strReserved.clear(); -} - -std::string CUnsignedAlert::ToString() const -{ - std::string strSetCancel; - BOOST_FOREACH(int n, setCancel) - strSetCancel += strprintf("%d ", n); - std::string strSetSubVer; - BOOST_FOREACH(const std::string& str, setSubVer) - strSetSubVer += "\"" + str + "\" "; - return strprintf( - "CAlert(\n" - " nVersion = %d\n" - " nRelayUntil = %d\n" - " nExpiration = %d\n" - " nID = %d\n" - " nCancel = %d\n" - " setCancel = %s\n" - " nMinVer = %d\n" - " nMaxVer = %d\n" - " setSubVer = %s\n" - " nPriority = %d\n" - " strComment = \"%s\"\n" - " strStatusBar = \"%s\"\n" - ")\n", - nVersion, - nRelayUntil, - nExpiration, - nID, - nCancel, - strSetCancel, - nMinVer, - nMaxVer, - strSetSubVer, - nPriority, - strComment, - strStatusBar); -} - -void CAlert::SetNull() -{ - CUnsignedAlert::SetNull(); - vchMsg.clear(); - vchSig.clear(); -} - -bool CAlert::IsNull() const -{ - return (nExpiration == 0); -} - -uint256 CAlert::GetHash() const -{ - return Hash(this->vchMsg.begin(), this->vchMsg.end()); -} - -bool CAlert::IsInEffect() const -{ - return (GetAdjustedTime() < nExpiration); -} - -bool CAlert::Cancels(const CAlert& alert) const -{ - if (!IsInEffect()) - return false; // this was a no-op before 31403 - return (alert.nID <= nCancel || setCancel.count(alert.nID)); -} - -bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const -{ - // TODO: rework for client-version-embedded-in-strSubVer ? - return (IsInEffect() && - nMinVer <= nVersion && nVersion <= nMaxVer && - (setSubVer.empty() || setSubVer.count(strSubVerIn))); -} - -bool CAlert::AppliesToMe() const -{ - return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>())); -} - -bool CAlert::RelayTo(CNode* pnode) const -{ - if (!IsInEffect()) - return false; - // don't relay to nodes which haven't sent their version message - if (pnode->nVersion == 0) - return false; - // returns true if wasn't already contained in the set - if (pnode->setKnown.insert(GetHash()).second) - { - if (AppliesTo(pnode->nVersion, pnode->strSubVer) || - AppliesToMe() || - GetAdjustedTime() < nRelayUntil) - { - pnode->PushMessage(NetMsgType::ALERT, *this); - return true; - } - } - return false; -} - -bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const -{ - CPubKey key(alertKey); - if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) - return error("CAlert::CheckSignature(): verify signature failed"); - - // Now unserialize the data - CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); - sMsg >> *(CUnsignedAlert*)this; - return true; -} - -CAlert CAlert::getAlertByHash(const uint256 &hash) -{ - CAlert retval; - { - LOCK(cs_mapAlerts); - map<uint256, CAlert>::iterator mi = mapAlerts.find(hash); - if(mi != mapAlerts.end()) - retval = mi->second; - } - return retval; -} - -bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread) -{ - if (!CheckSignature(alertKey)) - return false; - if (!IsInEffect()) - return false; - - // alert.nID=max is reserved for if the alert key is - // compromised. It must have a pre-defined message, - // must never expire, must apply to all versions, - // and must cancel all previous - // alerts or it will be ignored (so an attacker can't - // send an "everything is OK, don't panic" version that - // cannot be overridden): - int maxInt = std::numeric_limits<int>::max(); - if (nID == maxInt) - { - if (!( - nExpiration == maxInt && - nCancel == (maxInt-1) && - nMinVer == 0 && - nMaxVer == maxInt && - setSubVer.empty() && - nPriority == maxInt && - strStatusBar == "URGENT: Alert key compromised, upgrade required" - )) - return false; - } - - { - LOCK(cs_mapAlerts); - // Cancel previous alerts - for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) - { - const CAlert& alert = (*mi).second; - if (Cancels(alert)) - { - LogPrint("alert", "cancelling alert %d\n", alert.nID); - uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); - mapAlerts.erase(mi++); - } - else if (!alert.IsInEffect()) - { - LogPrint("alert", "expiring alert %d\n", alert.nID); - uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); - mapAlerts.erase(mi++); - } - else - mi++; - } - - // Check if this alert has been cancelled - BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - { - const CAlert& alert = item.second; - if (alert.Cancels(*this)) - { - LogPrint("alert", "alert already cancelled by %d\n", alert.nID); - return false; - } - } - - // Add to mapAlerts - mapAlerts.insert(make_pair(GetHash(), *this)); - // Notify UI and -alertnotify if it applies to me - if(AppliesToMe()) - { - uiInterface.NotifyAlertChanged(GetHash(), CT_NEW); - Notify(strStatusBar, fThread); - } - } - - LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe()); - return true; -} - -void -CAlert::Notify(const std::string& strMessage, bool fThread) -{ - std::string strCmd = GetArg("-alertnotify", ""); - if (strCmd.empty()) return; - - // Alert text should be plain ascii coming from a trusted source, but to - // be safe we first strip anything not in safeChars, then add single quotes around - // the whole string before passing it to the shell: - std::string singleQuote("'"); - std::string safeStatus = SanitizeString(strMessage); - safeStatus = singleQuote+safeStatus+singleQuote; - boost::replace_all(strCmd, "%s", safeStatus); - - if (fThread) - boost::thread t(runCommand, strCmd); // thread runs free - else - runCommand(strCmd); -} diff --git a/src/alert.h b/src/alert.h deleted file mode 100644 index 8cb86e338c..0000000000 --- a/src/alert.h +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2015 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_ALERT_H -#define BITCOIN_ALERT_H - -#include "serialize.h" -#include "sync.h" - -#include <map> -#include <set> -#include <stdint.h> -#include <string> - -class CAlert; -class CNode; -class uint256; - -extern std::map<uint256, CAlert> mapAlerts; -extern CCriticalSection cs_mapAlerts; - -/** Alerts are for notifying old versions if they become too obsolete and - * need to upgrade. The message is displayed in the status bar. - * Alert messages are broadcast as a vector of signed data. Unserializing may - * not read the entire buffer if the alert is for a newer version, but older - * versions can still relay the original data. - */ -class CUnsignedAlert -{ -public: - int nVersion; - int64_t nRelayUntil; // when newer nodes stop relaying to newer nodes - int64_t nExpiration; - int nID; - int nCancel; - std::set<int> setCancel; - int nMinVer; // lowest version inclusive - int nMaxVer; // highest version inclusive - std::set<std::string> setSubVer; // empty matches all - int nPriority; - - // Actions - std::string strComment; - std::string strStatusBar; - std::string strReserved; - - ADD_SERIALIZE_METHODS; - - template <typename Stream, typename Operation> - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(this->nVersion); - nVersion = this->nVersion; - READWRITE(nRelayUntil); - READWRITE(nExpiration); - READWRITE(nID); - READWRITE(nCancel); - READWRITE(setCancel); - READWRITE(nMinVer); - READWRITE(nMaxVer); - READWRITE(setSubVer); - READWRITE(nPriority); - - READWRITE(LIMITED_STRING(strComment, 65536)); - READWRITE(LIMITED_STRING(strStatusBar, 256)); - READWRITE(LIMITED_STRING(strReserved, 256)); - } - - void SetNull(); - - std::string ToString() const; -}; - -/** An alert is a combination of a serialized CUnsignedAlert and a signature. */ -class CAlert : public CUnsignedAlert -{ -public: - std::vector<unsigned char> vchMsg; - std::vector<unsigned char> vchSig; - - CAlert() - { - SetNull(); - } - - ADD_SERIALIZE_METHODS; - - template <typename Stream, typename Operation> - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(vchMsg); - READWRITE(vchSig); - } - - void SetNull(); - bool IsNull() const; - uint256 GetHash() const; - bool IsInEffect() const; - bool Cancels(const CAlert& alert) const; - bool AppliesTo(int nVersion, const std::string& strSubVerIn) const; - bool AppliesToMe() const; - bool RelayTo(CNode* pnode) const; - bool CheckSignature(const std::vector<unsigned char>& alertKey) const; - bool ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread = true); // fThread means run -alertnotify in a free-running thread - static void Notify(const std::string& strMessage, bool fThread); - - /* - * Get copy of (active) alert object by hash. Returns a null alert if it is not found. - */ - static CAlert getAlertByHash(const uint256 &hash); -}; - -#endif // BITCOIN_ALERT_H diff --git a/src/amount.cpp b/src/amount.cpp index a3abd8cd83..68806ff062 100644 --- a/src/amount.cpp +++ b/src/amount.cpp @@ -19,10 +19,10 @@ CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nSize) CAmount CFeeRate::GetFee(size_t nSize) const { - CAmount nFee = nSatoshisPerK*nSize / 1000; + CAmount nFee = nSatoshisPerK * nSize / 1000; - if (nFee == 0 && nSatoshisPerK > 0) - nFee = nSatoshisPerK; + if (nFee == 0 && nSize != 0 && nSatoshisPerK > 0) + nFee = CAmount(1); return nFee; } diff --git a/src/amount.h b/src/amount.h index a48b17d514..9aba6525c7 100644 --- a/src/amount.h +++ b/src/amount.h @@ -42,10 +42,14 @@ public: explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { } CFeeRate(const CAmount& nFeePaid, size_t nSize); CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; } - - CAmount GetFee(size_t size) const; // unit returned is satoshis - CAmount GetFeePerK() const { return GetFee(1000); } // satoshis-per-1000-bytes - + /** + * Return the fee in satoshis for the given size in bytes. + */ + CAmount GetFee(size_t size) const; + /** + * Return the fee in satoshis for a size of 1000 bytes + */ + CAmount GetFeePerK() const { return GetFee(1000); } friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; } friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; } friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; } diff --git a/src/base58.cpp b/src/base58.cpp index 5e26cf8d47..d81c26092c 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -68,26 +68,31 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) { // Skip & count leading zeroes. int zeroes = 0; + int length = 0; while (pbegin != pend && *pbegin == 0) { pbegin++; zeroes++; } // Allocate enough space in big-endian base58 representation. - std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up. + int size = (pend - pbegin) * 138 / 100 + 1; // log(256) / log(58), rounded up. + std::vector<unsigned char> b58(size); // Process the bytes. while (pbegin != pend) { int carry = *pbegin; + int i = 0; // Apply "b58 = b58 * 256 + ch". - for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) { + for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); (carry != 0 || i < length) && (it != b58.rend()); it++, i++) { carry += 256 * (*it); *it = carry % 58; carry /= 58; } + assert(carry == 0); + length = i; pbegin++; } // Skip leading zeroes in base58 result. - std::vector<unsigned char>::iterator it = b58.begin(); + std::vector<unsigned char>::iterator it = b58.begin() + (size - length); while (it != b58.end() && *it == 0) it++; // Translate the result into a string. diff --git a/src/chain.h b/src/chain.h index 9199983565..5b9605a80b 100644 --- a/src/chain.h +++ b/src/chain.h @@ -14,8 +14,6 @@ #include <vector> -#include <boost/foreach.hpp> - struct CDiskBlockPos { int nFile; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index b962f6ac0a..508c4de167 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -81,6 +81,11 @@ public: consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; + consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 + consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 /** * The message start string is designed to be unlikely to occur in normal data. * The characters are rarely used upper ASCII, not valid as UTF-8, and produce @@ -90,7 +95,6 @@ public: pchMessageStart[1] = 0xbe; pchMessageStart[2] = 0xb4; pchMessageStart[3] = 0xd9; - vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"); nDefaultPort = 8333; nPruneAfterHeight = 100000; @@ -162,11 +166,15 @@ public: consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = false; + consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains + consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 pchMessageStart[0] = 0x0b; pchMessageStart[1] = 0x11; pchMessageStart[2] = 0x09; pchMessageStart[3] = 0x07; - vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"); nDefaultPort = 18333; nPruneAfterHeight = 1000; @@ -225,6 +233,11 @@ public: consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = true; + consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains + consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016) + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL; pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xbf; diff --git a/src/chainparams.h b/src/chainparams.h index 88bc666765..59202f548a 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -54,7 +54,6 @@ public: const Consensus::Params& GetConsensus() const { return consensus; } const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } - const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } const CBlock& GenesisBlock() const { return genesis; } @@ -80,8 +79,6 @@ protected: Consensus::Params consensus; CMessageHeader::MessageStartChars pchMessageStart; - //! Raw pub key bytes for the broadcast alert signing key. - std::vector<unsigned char> vAlertPubKey; int nDefaultPort; uint64_t nPruneAfterHeight; std::vector<CDNSSeedData> vSeeds; diff --git a/src/consensus/params.h b/src/consensus/params.h index 335750fe80..7c3a8e84c3 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -7,8 +7,29 @@ #define BITCOIN_CONSENSUS_PARAMS_H #include "uint256.h" +#include <map> +#include <string> namespace Consensus { + +enum DeploymentPos +{ + DEPLOYMENT_TESTDUMMY, + MAX_VERSION_BITS_DEPLOYMENTS +}; + +/** + * Struct for each individual consensus rule change using BIP9. + */ +struct BIP9Deployment { + /** Bit position to select the particular bit in nVersion. */ + int bit; + /** Start MedianTime for version bits miner confirmation. Can be a date in the past */ + int64_t nStartTime; + /** Timeout/expiry MedianTime for the deployment attempt. */ + int64_t nTimeout; +}; + /** * Parameters that influence chain consensus. */ @@ -22,6 +43,14 @@ struct Params { /** Block height and hash at which BIP34 becomes active */ int BIP34Height; uint256 BIP34Hash; + /** + * Minimum blocks including miner confirmation of the total of 2016 blocks in a retargetting period, + * (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments. + * Examples: 1916 for 95%, 1512 for testchains. + */ + uint32_t nRuleChangeActivationThreshold; + uint32_t nMinerConfirmationWindow; + BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS]; /** Proof of work parameters */ uint256 powLimit; bool fPowAllowMinDifficultyBlocks; diff --git a/src/httprpc.cpp b/src/httprpc.cpp index a447a3eff8..04d3386e9a 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -219,7 +219,7 @@ static bool InitRPCAuthentication() return false; } } else { - LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation."); + LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation.\n"); strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; } return true; diff --git a/src/init.cpp b/src/init.cpp index 048843a4c1..38ac91b2af 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -72,7 +72,6 @@ static const bool DEFAULT_REST_ENABLE = false; static const bool DEFAULT_DISABLE_SAFEMODE = false; static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; -static const char * const DEFAULT_WALLET_DAT = "wallet.dat"; #if ENABLE_ZMQ static CZMQNotificationInterface* pzmqNotificationInterface = NULL; @@ -196,7 +195,6 @@ void Shutdown() if (pwalletMain) pwalletMain->Flush(false); #endif - GenerateBitcoins(false, 0, Params()); StopNode(); StopTorControl(); UnregisterNodeSignals(GetNodeSignals()); @@ -317,7 +315,6 @@ std::string HelpMessage(HelpMessageMode mode) string strUsage = HelpMessageGroup(_("Options:")); strUsage += HelpMessageOpt("-?", _("Print this help message and exit")); strUsage += HelpMessageOpt("-version", _("Print version and exit")); - strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS)); strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)")); strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)")); if (showDebug) @@ -333,6 +330,7 @@ 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)); 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)); @@ -371,8 +369,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-onlynet=<net>", _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)")); strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), DEFAULT_PERMIT_BAREMULTISIG)); strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with bloom filters (default: %u)"), DEFAULT_PEERBLOOMFILTERS)); - if (showDebug) - strUsage += HelpMessageOpt("-enforcenodebloom", strprintf("Enforce minimum protocol version to limit use of bloom filters (default: %u)", DEFAULT_ENFORCENODEBLOOM)); strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort())); strUsage += HelpMessageOpt("-proxy=<ip:port>", _("Connect through SOCKS5 proxy")); strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE)); @@ -395,26 +391,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET)); #ifdef ENABLE_WALLET - strUsage += HelpMessageGroup(_("Wallet options:")); - strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); - strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE)); - strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"), - CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE))); - strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"), - CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE))); - strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), - CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); - strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup")); - strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet.dat on startup")); - strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS)); - strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE)); - strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET)); - strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup")); - strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT)); - strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST)); - strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); - strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") + - " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)")); + strUsage += CWallet::GetWalletHelpString(showDebug); #endif #if ENABLE_ZMQ @@ -432,16 +409,10 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); strUsage += HelpMessageOpt("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED)); -#ifdef ENABLE_WALLET - strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE)); -#endif strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", DEFAULT_DISABLE_SAFEMODE)); strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", DEFAULT_TESTSAFEMODE)); strUsage += HelpMessageOpt("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages"); strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages"); -#ifdef ENABLE_WALLET - strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET)); -#endif strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT)); strUsage += HelpMessageOpt("-limitancestorcount=<n>", strprintf("Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)", DEFAULT_ANCESTOR_LIMIT)); strUsage += HelpMessageOpt("-limitancestorsize=<n>", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT)); @@ -455,8 +426,6 @@ std::string HelpMessage(HelpMessageMode mode) _("If <category> is not supplied or if <category> = 1, output all debugging information.") + _("<category> can be:") + " " + debugCategories + "."); if (showDebug) strUsage += HelpMessageOpt("-nodebug", "Turn off debugging messages, same as -debug=0"); - strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), DEFAULT_GENERATE)); - strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), DEFAULT_GENERATE_THREADS)); strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)")); strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), DEFAULT_LOGIPS)); strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), DEFAULT_LOGTIMESTAMPS)); @@ -477,9 +446,6 @@ std::string HelpMessage(HelpMessageMode mode) if (showDebug) { strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY)); -#ifdef ENABLE_WALLET - strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB)); -#endif } strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)")); @@ -498,7 +464,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE)); strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE)); if (showDebug) - strUsage += HelpMessageOpt("-blockversion=<n>", strprintf("Override block version to test forking scenarios (default: %d)", (int)CBlock::CURRENT_VERSION)); + strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios"); strUsage += HelpMessageGroup(_("RPC server options:")); strUsage += HelpMessageOpt("-server", _("Accept command line and JSON-RPC commands")); @@ -1034,8 +1000,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes); - fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS); - // Option to startup with mocktime set (used for regression testing): SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op @@ -1091,14 +1055,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (fPrintToDebugLog) OpenDebugLog(); -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) - LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION)); -#elif defined OPENSSL_VERSION - LogPrintf("Using OpenSSL version %s\n", OpenSSL_version(OPENSSL_VERSION)); -#elif defined LIBRESSL_VERSION_TEXT - LogPrintf("Using %s\n", LIBRESSL_VERSION_TEXT); -#endif - #ifdef ENABLE_WALLET LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); #endif @@ -1199,6 +1155,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // -proxy sets a proxy for all outgoing network traffic // -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default std::string proxyArg = GetArg("-proxy", ""); + SetLimited(NET_TOR); if (proxyArg != "" && proxyArg != "0") { proxyType addrProxy = proxyType(CService(proxyArg, 9050), proxyRandomize); if (!addrProxy.IsValid()) @@ -1208,7 +1165,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) SetProxy(NET_IPV6, addrProxy); SetProxy(NET_TOR, addrProxy); SetNameProxy(addrProxy); - SetReachable(NET_TOR); // by default, -proxy sets onion as reachable, unless -noonion later + SetLimited(NET_TOR, false); // by default, -proxy sets onion as reachable, unless -noonion later } // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses @@ -1217,13 +1174,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) std::string onionArg = GetArg("-onion", ""); if (onionArg != "") { if (onionArg == "0") { // Handle -noonion/-onion=0 - SetReachable(NET_TOR, false); // set onions as unreachable + SetLimited(NET_TOR); // set onions as unreachable } else { proxyType addrOnion = proxyType(CService(onionArg, 9050), proxyRandomize); if (!addrOnion.IsValid()) return InitError(strprintf(_("Invalid -onion address: '%s'"), onionArg)); SetProxy(NET_TOR, addrOnion); - SetReachable(NET_TOR); + SetLimited(NET_TOR, false); } } @@ -1460,149 +1417,19 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) pwalletMain = NULL; LogPrintf("Wallet disabled!\n"); } else { - - // needed to restore wallet transaction meta data after -zapwallettxes - std::vector<CWalletTx> vWtx; - - if (GetBoolArg("-zapwallettxes", false)) { - uiInterface.InitMessage(_("Zapping all transactions from wallet...")); - - pwalletMain = new CWallet(strWalletFile); - DBErrors nZapWalletRet = pwalletMain->ZapWalletTx(vWtx); - if (nZapWalletRet != DB_LOAD_OK) { - uiInterface.InitMessage(_("Error loading wallet.dat: Wallet corrupted")); - return false; - } - - delete pwalletMain; - pwalletMain = NULL; - } - - uiInterface.InitMessage(_("Loading wallet...")); - - nStart = GetTimeMillis(); - bool fFirstRun = true; - pwalletMain = new CWallet(strWalletFile); - DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun); - if (nLoadWalletRet != DB_LOAD_OK) - { - if (nLoadWalletRet == DB_CORRUPT) - strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n"; - else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) - { - InitWarning(_("Error reading wallet.dat! All keys read correctly, but transaction data" - " or address book entries might be missing or incorrect.")); - } - else if (nLoadWalletRet == DB_TOO_NEW) - strErrors << strprintf(_("Error loading wallet.dat: Wallet requires newer version of %s"), _(PACKAGE_NAME)) << "\n"; - else if (nLoadWalletRet == DB_NEED_REWRITE) - { - strErrors << strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)) << "\n"; - LogPrintf("%s", strErrors.str()); - return InitError(strErrors.str()); - } - else - strErrors << _("Error loading wallet.dat") << "\n"; - } - - if (GetBoolArg("-upgradewallet", fFirstRun)) - { - int nMaxVersion = GetArg("-upgradewallet", 0); - if (nMaxVersion == 0) // the -upgradewallet without argument case - { - LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST); - nMaxVersion = CLIENT_VERSION; - pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately - } - else - LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion); - if (nMaxVersion < pwalletMain->GetVersion()) - strErrors << _("Cannot downgrade wallet") << "\n"; - pwalletMain->SetMaxVersion(nMaxVersion); - } - - if (fFirstRun) - { - // Create new keyUser and set as default key - RandAddSeedPerfmon(); - - CPubKey newDefaultKey; - if (pwalletMain->GetKeyFromPool(newDefaultKey)) { - pwalletMain->SetDefaultKey(newDefaultKey); - if (!pwalletMain->SetAddressBook(pwalletMain->vchDefaultKey.GetID(), "", "receive")) - strErrors << _("Cannot write default address") << "\n"; - } - - pwalletMain->SetBestChain(chainActive.GetLocator()); - } - - LogPrintf("%s", strErrors.str()); - LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart); - - RegisterValidationInterface(pwalletMain); - - CBlockIndex *pindexRescan = chainActive.Tip(); - if (GetBoolArg("-rescan", false)) - pindexRescan = chainActive.Genesis(); - else - { - CWalletDB walletdb(strWalletFile); - CBlockLocator locator; - if (walletdb.ReadBestBlock(locator)) - pindexRescan = FindForkInGlobalIndex(chainActive, locator); - else - pindexRescan = chainActive.Genesis(); - } - if (chainActive.Tip() && chainActive.Tip() != pindexRescan) + std::string warningString; + std::string errorString; + pwalletMain = CWallet::InitLoadWallet(fDisableWallet, strWalletFile, warningString, errorString); + if (!warningString.empty()) + InitWarning(warningString); + if (!errorString.empty()) { - //We can't rescan beyond non-pruned blocks, stop and throw an error - //this might happen if a user uses a old wallet within a pruned node - // or if he ran -disablewallet for a longer time, then decided to re-enable - if (fPruneMode) - { - CBlockIndex *block = chainActive.Tip(); - while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block) - block = block->pprev; - - if (pindexRescan != block) - return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)")); - } - - uiInterface.InitMessage(_("Rescanning...")); - LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight); - nStart = GetTimeMillis(); - pwalletMain->ScanForWalletTransactions(pindexRescan, true); - LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); - pwalletMain->SetBestChain(chainActive.GetLocator()); - nWalletDBUpdated++; - - // Restore wallet transaction metadata after -zapwallettxes=1 - if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") - { - CWalletDB walletdb(strWalletFile); - - BOOST_FOREACH(const CWalletTx& wtxOld, vWtx) - { - uint256 hash = wtxOld.GetHash(); - std::map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash); - if (mi != pwalletMain->mapWallet.end()) - { - const CWalletTx* copyFrom = &wtxOld; - CWalletTx* copyTo = &mi->second; - copyTo->mapValue = copyFrom->mapValue; - copyTo->vOrderForm = copyFrom->vOrderForm; - copyTo->nTimeReceived = copyFrom->nTimeReceived; - copyTo->nTimeSmart = copyFrom->nTimeSmart; - copyTo->fFromMe = copyFrom->fFromMe; - copyTo->strFromAccount = copyFrom->strFromAccount; - copyTo->nOrderPos = copyFrom->nOrderPos; - copyTo->WriteToDisk(&walletdb); - } - } - } + LogPrintf("%s", errorString); + return InitError(errorString); } - pwalletMain->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); - } // (!fDisableWallet) + if (!pwalletMain) + return false; + } #else // ENABLE_WALLET LogPrintf("No wallet support compiled in!\n"); #endif // !ENABLE_WALLET @@ -1674,9 +1501,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing); scheduler.scheduleEvery(f, nPowTargetSpacing); - // Generate coins in the background - GenerateBitcoins(GetBoolArg("-gen", DEFAULT_GENERATE), GetArg("-genproclimit", DEFAULT_GENERATE_THREADS), chainparams); - // ********************************************************* Step 12: finished SetRPCWarmupFinished(); diff --git a/src/main.cpp b/src/main.cpp index babdff54ef..36189f4ffc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,7 +6,6 @@ #include "main.h" #include "addrman.h" -#include "alert.h" #include "arith_uint256.h" #include "chainparams.h" #include "checkpoints.h" @@ -18,10 +17,12 @@ #include "init.h" #include "merkleblock.h" #include "net.h" +#include "policy/fees.h" #include "policy/policy.h" #include "pow.h" #include "primitives/block.h" #include "primitives/transaction.h" +#include "random.h" #include "script/script.h" #include "script/sigcache.h" #include "script/standard.h" @@ -34,6 +35,7 @@ #include "utilmoneystr.h" #include "utilstrencodings.h" #include "validationinterface.h" +#include "versionbits.h" #include <sstream> @@ -74,7 +76,6 @@ bool fCheckBlockIndex = false; bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED; size_t nCoinCacheUsage = 5000 * 300; uint64_t nPruneTarget = 0; -bool fAlerts = DEFAULT_ALERTS; int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; @@ -82,6 +83,7 @@ CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; CTxMemPool mempool(::minRelayTxFee); +FeeFilterRounder filterRounder(::minRelayTxFee); struct COrphanTx { CTransaction tx; @@ -794,7 +796,25 @@ bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeig return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block)); } -bool CheckSequenceLocks(const CTransaction &tx, int flags) +bool TestLockPointValidity(const LockPoints* lp) +{ + AssertLockHeld(cs_main); + assert(lp); + // If there are relative lock times then the maxInputBlock will be set + // If there are no relative lock times, the LockPoints don't depend on the chain + if (lp->maxInputBlock) { + // Check whether chainActive is an extension of the block at which the LockPoints + // calculation was valid. If not LockPoints are no longer valid + if (!chainActive.Contains(lp->maxInputBlock)) { + return false; + } + } + + // LockPoints still valid + return true; +} + +bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool useExistingLockPoints) { AssertLockHeld(cs_main); AssertLockHeld(mempool.cs); @@ -810,25 +830,57 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags) // *next* block, we need to use one more than chainActive.Height() index.nHeight = tip->nHeight + 1; - // pcoinsTip contains the UTXO set for chainActive.Tip() - CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); - std::vector<int> prevheights; - prevheights.resize(tx.vin.size()); - for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { - const CTxIn& txin = tx.vin[txinIndex]; - CCoins coins; - if (!viewMemPool.GetCoins(txin.prevout.hash, coins)) { - return error("%s: Missing input", __func__); + std::pair<int, int64_t> lockPair; + if (useExistingLockPoints) { + assert(lp); + lockPair.first = lp->height; + lockPair.second = lp->time; + } + else { + // pcoinsTip contains the UTXO set for chainActive.Tip() + CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); + std::vector<int> prevheights; + prevheights.resize(tx.vin.size()); + for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { + const CTxIn& txin = tx.vin[txinIndex]; + CCoins coins; + if (!viewMemPool.GetCoins(txin.prevout.hash, coins)) { + return error("%s: Missing input", __func__); + } + if (coins.nHeight == MEMPOOL_HEIGHT) { + // Assume all mempool transaction confirm in the next block + prevheights[txinIndex] = tip->nHeight + 1; + } else { + prevheights[txinIndex] = coins.nHeight; + } } - if (coins.nHeight == MEMPOOL_HEIGHT) { - // Assume all mempool transaction confirm in the next block - prevheights[txinIndex] = tip->nHeight + 1; - } else { - prevheights[txinIndex] = coins.nHeight; + lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index); + if (lp) { + lp->height = lockPair.first; + lp->time = lockPair.second; + // Also store the hash of the block with the highest height of + // all the blocks which have sequence locked prevouts. + // This hash needs to still be on the chain + // for these LockPoint calculations to be valid + // Note: It is impossible to correctly calculate a maxInputBlock + // if any of the sequence locked inputs depend on unconfirmed txs, + // except in the special case where the relative lock time/height + // is 0, which is equivalent to no sequence lock. Since we assume + // input height of tip+1 for mempool txs and test the resulting + // lockPair from CalculateSequenceLocks against tip+1. We know + // EvaluateSequenceLocks will fail if there was a non-zero sequence + // lock on a mempool input, so we can use the return value of + // CheckSequenceLocks to indicate the LockPoints validity + int maxInputHeight = 0; + BOOST_FOREACH(int height, prevheights) { + // Can ignore mempool inputs since we'll fail if they had non-zero locks + if (height != tip->nHeight+1) { + maxInputHeight = std::max(maxInputHeight, height); + } + } + lp->maxInputBlock = tip->GetAncestor(maxInputHeight); } } - - std::pair<int, int64_t> lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index); return EvaluateSequenceLocks(index, lockPair); } @@ -938,7 +990,7 @@ std::string FormatStateMessage(const CValidationState &state) } bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, - bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee, + bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee, std::vector<uint256>& vHashTxnToUncache) { const uint256 hash = tx.GetHash(); @@ -947,7 +999,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C *pfMissingInputs = false; if (!CheckTransaction(tx, state)) - return error("%s: CheckTransaction: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); + return false; // state filled in by CheckTransaction // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) @@ -1017,6 +1069,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C CCoinsViewCache view(&dummy); CAmount nValueIn = 0; + LockPoints lp; { LOCK(pool.cs); CCoinsViewMemPool viewMemPool(pcoinsTip, pool); @@ -1060,7 +1113,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // be mined yet. // Must keep pool.cs for this unless we change CheckSequenceLocks to take a // CoinsViewCache instead of create its own - if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) + if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final"); } @@ -1092,8 +1145,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C } } - CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps); + CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp); unsigned int nSize = entry.GetTxSize(); + if (txFeeRate) { + *txFeeRate = CFeeRate(nFees, nSize); + } // Check that the transaction doesn't have an excessive number of // sigops, making it impossible to mine. Since the coinbase transaction @@ -1160,10 +1216,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C const uint256 &hashAncestor = ancestorIt->GetTx().GetHash(); if (setConflicts.count(hashAncestor)) { - return state.DoS(10, error("AcceptToMemoryPool: %s spends conflicting transaction %s", + return state.DoS(10, false, + REJECT_INVALID, "bad-txns-spends-conflicting-tx", false, + strprintf("%s spends conflicting transaction %s", hash.ToString(), - hashAncestor.ToString()), - REJECT_INVALID, "bad-txns-spends-conflicting-tx"); + hashAncestor.ToString())); } } @@ -1193,20 +1250,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // Save these to avoid repeated lookups setIterConflicting.insert(mi); - // If this entry is "dirty", then we don't have descendant - // state for this transaction, which means we probably have - // lots of in-mempool descendants. - // Don't allow replacements of dirty transactions, to ensure - // that we don't spend too much time walking descendants. - // This should be rare. - if (mi->IsDirty()) { - return state.DoS(0, - error("AcceptToMemoryPool: rejecting replacement %s; cannot replace tx %s with untracked descendants", - hash.ToString(), - mi->GetTx().GetHash().ToString()), - REJECT_NONSTANDARD, "too many potential replacements"); - } - // Don't allow the replacement to reduce the feerate of the // mempool. // @@ -1226,12 +1269,12 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize()); if (newFeeRate <= oldFeeRate) { - return state.DoS(0, - error("AcceptToMemoryPool: rejecting replacement %s; new feerate %s <= old feerate %s", + return state.DoS(0, false, + REJECT_INSUFFICIENTFEE, "insufficient fee", false, + strprintf("rejecting replacement %s; new feerate %s <= old feerate %s", hash.ToString(), newFeeRate.ToString(), - oldFeeRate.ToString()), - REJECT_INSUFFICIENTFEE, "insufficient fee"); + oldFeeRate.ToString())); } BOOST_FOREACH(const CTxIn &txin, mi->GetTx().vin) @@ -1255,12 +1298,12 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C nConflictingSize += it->GetTxSize(); } } else { - return state.DoS(0, - error("AcceptToMemoryPool: rejecting replacement %s; too many potential replacements (%d > %d)\n", + return state.DoS(0, false, + REJECT_NONSTANDARD, "too many potential replacements", false, + strprintf("rejecting replacement %s; too many potential replacements (%d > %d)\n", hash.ToString(), nConflictingCount, - maxDescendantsToVisit), - REJECT_NONSTANDARD, "too many potential replacements"); + maxDescendantsToVisit)); } for (unsigned int j = 0; j < tx.vin.size(); j++) @@ -1275,9 +1318,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // it's cheaper to just check if the new input refers to a // tx that's in the mempool. if (pool.mapTx.find(tx.vin[j].prevout.hash) != pool.mapTx.end()) - return state.DoS(0, error("AcceptToMemoryPool: replacement %s adds unconfirmed input, idx %d", - hash.ToString(), j), - REJECT_NONSTANDARD, "replacement-adds-unconfirmed"); + return state.DoS(0, false, + REJECT_NONSTANDARD, "replacement-adds-unconfirmed", false, + strprintf("replacement %s adds unconfirmed input, idx %d", + hash.ToString(), j)); } } @@ -1286,9 +1330,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // transactions would not be paid for. if (nModifiedFees < nConflictingFees) { - return state.DoS(0, error("AcceptToMemoryPool: rejecting replacement %s, less fees than conflicting txs; %s < %s", - hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)), - REJECT_INSUFFICIENTFEE, "insufficient fee"); + return state.DoS(0, false, + REJECT_INSUFFICIENTFEE, "insufficient fee", false, + strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s", + hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees))); } // Finally in addition to paying more fees than the conflicts the @@ -1296,19 +1341,19 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C CAmount nDeltaFees = nModifiedFees - nConflictingFees; if (nDeltaFees < ::minRelayTxFee.GetFee(nSize)) { - return state.DoS(0, - error("AcceptToMemoryPool: rejecting replacement %s, not enough additional fees to relay; %s < %s", + return state.DoS(0, false, + REJECT_INSUFFICIENTFEE, "insufficient fee", false, + strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s", hash.ToString(), FormatMoney(nDeltaFees), - FormatMoney(::minRelayTxFee.GetFee(nSize))), - REJECT_INSUFFICIENTFEE, "insufficient fee"); + FormatMoney(::minRelayTxFee.GetFee(nSize)))); } } // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true)) - return error("%s: CheckInputs: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); + return false; // state filled in by CheckInputs // Check again against just the consensus-critical mandatory script // verification flags, in case of bugs in the standard flags that cause @@ -1334,7 +1379,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C FormatMoney(nModifiedFees - nConflictingFees), (int)nSize - (int)nConflictingSize); } - pool.RemoveStaged(allConflicting); + pool.RemoveStaged(allConflicting, false); // Store transaction in memory pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload()); @@ -1353,10 +1398,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C } bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, - bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee) + bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount nAbsurdFee) { std::vector<uint256> vHashTxToUncache; - bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache); + bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, txFeeRate, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache); if (!res) { BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache) pcoinsTip->Uncache(hashTx); @@ -1525,6 +1570,26 @@ bool fLargeWorkForkFound = false; bool fLargeWorkInvalidChainFound = false; CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL; +static void AlertNotify(const std::string& strMessage, bool fThread) +{ + uiInterface.NotifyAlertChanged(); + std::string strCmd = GetArg("-alertnotify", ""); + if (strCmd.empty()) return; + + // Alert text should be plain ascii coming from a trusted source, but to + // be safe we first strip anything not in safeChars, then add single quotes around + // the whole string before passing it to the shell: + std::string singleQuote("'"); + std::string safeStatus = SanitizeString(strMessage); + safeStatus = singleQuote+safeStatus+singleQuote; + boost::replace_all(strCmd, "%s", safeStatus); + + if (fThread) + boost::thread t(runCommand, strCmd); // thread runs free + else + runCommand(strCmd); +} + void CheckForkWarningConditions() { AssertLockHeld(cs_main); @@ -1544,7 +1609,7 @@ void CheckForkWarningConditions() { std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + pindexBestForkBase->phashBlock->ToString() + std::string("'"); - CAlert::Notify(warning, true); + AlertNotify(warning, true); } if (pindexBestForkTip && pindexBestForkBase) { @@ -2075,11 +2140,56 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const if (!strWarning.empty()) { strMiscWarning = strWarning; - CAlert::Notify(strWarning, true); + AlertNotify(strWarning, true); lastAlertTime = now; } } +// Protected by cs_main +static VersionBitsCache versionbitscache; + +int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) +{ + LOCK(cs_main); + int32_t nVersion = VERSIONBITS_TOP_BITS; + + for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { + ThresholdState state = VersionBitsState(pindexPrev, params, (Consensus::DeploymentPos)i, versionbitscache); + if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) { + nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i); + } + } + + return nVersion; +} + +/** + * Threshold condition checker that triggers when unknown versionbits are seen on the network. + */ +class WarningBitsConditionChecker : public AbstractThresholdConditionChecker +{ +private: + int bit; + +public: + WarningBitsConditionChecker(int bitIn) : bit(bitIn) {} + + int64_t BeginTime(const Consensus::Params& params) const { return 0; } + int64_t EndTime(const Consensus::Params& params) const { return std::numeric_limits<int64_t>::max(); } + int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; } + int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; } + + bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const + { + return ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && + ((pindex->nVersion >> bit) & 1) != 0 && + ((ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0; + } +}; + +// Protected by cs_main +static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS]; + static int64_t nTimeCheck = 0; static int64_t nTimeForks = 0; static int64_t nTimeVerify = 0; @@ -2449,24 +2559,42 @@ void static UpdateTip(CBlockIndex *pindexNew) { // Check the version of the last 100 blocks to see if we need to upgrade: static bool fWarned = false; - if (!IsInitialBlockDownload() && !fWarned) + if (!IsInitialBlockDownload()) { int nUpgraded = 0; const CBlockIndex* pindex = chainActive.Tip(); + for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { + WarningBitsConditionChecker checker(bit); + ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]); + if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) { + if (state == THRESHOLD_ACTIVE) { + strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit); + if (!fWarned) { + AlertNotify(strMiscWarning, true); + fWarned = true; + } + } else { + LogPrintf("%s: unknown new rules are about to activate (versionbit %i)\n", __func__, bit); + } + } + } for (int i = 0; i < 100 && pindex != NULL; i++) { - if (pindex->nVersion > CBlock::CURRENT_VERSION) + int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus()); + if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0) ++nUpgraded; pindex = pindex->pprev; } if (nUpgraded > 0) - LogPrintf("%s: %d of last 100 blocks above version %d\n", __func__, nUpgraded, (int)CBlock::CURRENT_VERSION); + LogPrintf("%s: %d of last 100 blocks have unexpected version\n", __func__, nUpgraded); if (nUpgraded > 100/2) { // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: - strMiscWarning = _("Warning: This version is obsolete; upgrade required!"); - CAlert::Notify(strMiscWarning, true); - fWarned = true; + strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect"); + if (!fWarned) { + AlertNotify(strMiscWarning, true); + fWarned = true; + } } } } @@ -2498,8 +2626,8 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons // ignore validation errors in resurrected transactions list<CTransaction> removed; CValidationState stateDummy; - if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) { - mempool.remove(tx, removed, true); + if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, NULL, true)) { + mempool.removeRecursive(tx, removed); } else if (mempool.exists(tx.GetHash())) { vHashUpdate.push_back(tx.GetHash()); } @@ -3760,6 +3888,10 @@ void UnloadBlockIndex() setDirtyFileInfo.clear(); mapNodeState.clear(); recentRejects.reset(NULL); + versionbitscache.Clear(); + for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) { + warningcache[b].clear(); + } BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) { delete entry.second; @@ -4105,14 +4237,8 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams) assert(nNodes == forward.size()); } -////////////////////////////////////////////////////////////////////////////// -// -// CAlert -// - std::string GetWarnings(const std::string& strFor) { - int nPriority = 0; string strStatusBar; string strRPC; string strGUI; @@ -4128,37 +4254,20 @@ std::string GetWarnings(const std::string& strFor) // Misc warnings like out of disk space and clock is wrong if (strMiscWarning != "") { - nPriority = 1000; strStatusBar = strGUI = strMiscWarning; } if (fLargeWorkForkFound) { - nPriority = 2000; strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."; strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."); } else if (fLargeWorkInvalidChainFound) { - nPriority = 2000; strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."; strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); } - // Alerts - { - LOCK(cs_mapAlerts); - BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - { - const CAlert& alert = item.second; - if (alert.AppliesToMe() && alert.nPriority > nPriority) - { - nPriority = alert.nPriority; - strStatusBar = strGUI = alert.strStatusBar; - } - } - } - if (strFor == "gui") return strGUI; else if (strFor == "statusbar") @@ -4374,7 +4483,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (pfrom->nVersion >= NO_BLOOM_VERSION) { Misbehaving(pfrom->GetId(), 100); return false; - } else if (GetBoolArg("-enforcenodebloom", DEFAULT_ENFORCENODEBLOOM)) { + } else { pfrom->fDisconnect = true; return false; } @@ -4480,13 +4589,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } - // Relay alerts - { - LOCK(cs_mapAlerts); - BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - item.second.RelayTo(pfrom); - } - pfrom->fSuccessfullyConnected = true; string remoteAddr; @@ -4820,10 +4922,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->setAskFor.erase(inv.hash); mapAlreadyAskedFor.erase(inv); - if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) - { + CFeeRate txFeeRate = CFeeRate(0); + if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, &txFeeRate)) { mempool.check(pcoinsTip); - RelayTransaction(tx); + RelayTransaction(tx, txFeeRate); vWorkQueue.push_back(inv.hash); LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n", @@ -4854,10 +4956,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (setMisbehaving.count(fromPeer)) continue; - if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) - { + CFeeRate orphanFeeRate = CFeeRate(0); + if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2, &orphanFeeRate)) { LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); - RelayTransaction(orphanTx); + RelayTransaction(orphanTx, orphanFeeRate); vWorkQueue.push_back(orphanHash); vEraseQueue.push_back(orphanHash); } @@ -4910,7 +5012,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int nDoS = 0; if (!state.IsInvalid(nDoS) || nDoS == 0) { LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id); - RelayTransaction(tx); + RelayTransaction(tx, txFeeRate); } else { LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state)); } @@ -5064,13 +5166,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - // This asymmetric behavior for inbound and outbound connections was introduced - // to prevent a fingerprinting attack: an attacker can send specific fake addresses - // to users' AddrMan and later request them by sending getaddr messages. - // Making nodes which are behind NAT and can only make outgoing connections ignore - // the getaddr message mitigates the attack. - else if ((strCommand == NetMsgType::GETADDR) && (pfrom->fInbound)) + else if (strCommand == NetMsgType::GETADDR) { + // This asymmetric behavior for inbound and outbound connections was introduced + // to prevent a fingerprinting attack: an attacker can send specific fake addresses + // to users' AddrMan and later request them by sending getaddr messages. + // Making nodes which are behind NAT and can only make outgoing connections ignore + // the getaddr message mitigates the attack. + if (!pfrom->fInbound) { + LogPrint("net", "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom->id); + return true; + } + pfrom->vAddrToSend.clear(); vector<CAddress> vAddr = addrman.GetAddr(); BOOST_FOREACH(const CAddress &addr, vAddr) @@ -5099,6 +5206,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (!fInMemPool) continue; // another thread removed since queryHashes, maybe... if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue; } + if (pfrom->minFeeFilter) { + CFeeRate feeRate; + mempool.lookupFeeRate(hash, feeRate); + LOCK(pfrom->cs_feeFilter); + if (feeRate.GetFeePerK() < pfrom->minFeeFilter) + continue; + } vInv.push_back(inv); if (vInv.size() == MAX_INV_SZ) { pfrom->PushMessage(NetMsgType::INV, vInv); @@ -5189,37 +5303,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - else if (fAlerts && strCommand == NetMsgType::ALERT) - { - CAlert alert; - vRecv >> alert; - - uint256 alertHash = alert.GetHash(); - if (pfrom->setKnown.count(alertHash) == 0) - { - if (alert.ProcessAlert(chainparams.AlertKey())) - { - // Relay - pfrom->setKnown.insert(alertHash); - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - alert.RelayTo(pnode); - } - } - else { - // Small DoS penalty so peers that send us lots of - // duplicate/expired/invalid-signature/whatever alerts - // eventually get banned. - // This isn't a Misbehaving(100) (immediate ban) because the - // peer might be an older or different implementation with - // a different signature key, etc. - Misbehaving(pfrom->GetId(), 10); - } - } - } - - else if (strCommand == NetMsgType::FILTERLOAD) { CBloomFilter filter; @@ -5292,8 +5375,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } - else - { + else if (strCommand == NetMsgType::FEEFILTER) { + CAmount newFeeFilter = 0; + vRecv >> newFeeFilter; + if (MoneyRange(newFeeFilter)) { + { + LOCK(pfrom->cs_feeFilter); + pfrom->minFeeFilter = newFeeFilter; + } + LogPrint("net", "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->id); + } + } + + else { // Ignore unknown commands for extensibility LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id); } @@ -5775,6 +5869,29 @@ bool SendMessages(CNode* pto) if (!vGetData.empty()) pto->PushMessage(NetMsgType::GETDATA, vGetData); + // + // Message: feefilter + // + // We don't want white listed peers to filter txs to us if we have -whitelistforcerelay + if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && + !(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) { + CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(); + int64_t timeNow = GetTimeMicros(); + if (timeNow > pto->nextSendTimeFeeFilter) { + CAmount filterToSend = filterRounder.round(currentFilter); + if (filterToSend != pto->lastSentFeeFilter) { + pto->PushMessage(NetMsgType::FEEFILTER, filterToSend); + pto->lastSentFeeFilter = filterToSend; + } + pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL); + } + // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY + // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY. + else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter && + (currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) { + pto->nextSendTimeFeeFilter = timeNow + (insecure_rand() % MAX_FEEFILTER_CHANGE_DELAY) * 1000000; + } + } } return true; } @@ -5783,7 +5900,11 @@ bool SendMessages(CNode* pto) return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast)); } - +ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos) +{ + LOCK(cs_main); + return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache); +} class CMainCleanup { diff --git a/src/main.h b/src/main.h index 5ba2be251c..0bfcfab213 100644 --- a/src/main.h +++ b/src/main.h @@ -16,6 +16,7 @@ #include "net.h" #include "script/script_error.h" #include "sync.h" +#include "versionbits.h" #include <algorithm> #include <exception> @@ -39,9 +40,8 @@ class CValidationInterface; class CValidationState; struct CNodeStateStats; +struct LockPoints; -/** Default for accepting alerts from the P2P network. */ -static const bool DEFAULT_ALERTS = true; /** Default for DEFAULT_WHITELISTRELAY. */ static const bool DEFAULT_WHITELISTRELAY = true; /** Default for DEFAULT_WHITELISTFORCERELAY. */ @@ -102,6 +102,10 @@ static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30; /** Average delay between trickled inventory broadcasts in seconds. * Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */ static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5; +/** Average delay between feefilter broadcasts in seconds. */ +static const unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60; +/** Maximum feefilter broadcast delay after significant change. */ +static const unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60; static const unsigned int DEFAULT_LIMITFREERELAY = 15; static const bool DEFAULT_RELAYPRIORITY = true; @@ -117,12 +121,13 @@ static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100; static const bool DEFAULT_TESTSAFEMODE = false; /** Default for -mempoolreplacement */ static const bool DEFAULT_ENABLE_REPLACEMENT = true; +/** Default for using fee filter */ +static const bool DEFAULT_FEEFILTER = true; /** Maximum number of headers to announce when relaying blocks with headers message.*/ static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8; static const bool DEFAULT_PEERBLOOMFILTERS = true; -static const bool DEFAULT_ENFORCENODEBLOOM = false; struct BlockHasher { @@ -153,7 +158,6 @@ extern size_t nCoinCacheUsage; extern CFeeRate minRelayTxFee; /** Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendrawtransaction) */ extern CAmount maxTxFee; -extern bool fAlerts; /** If the tip is older than this (in seconds), the node is considered to be in initial block download. */ extern int64_t nMaxTipAge; extern bool fEnableReplacement; @@ -284,11 +288,14 @@ void PruneAndFlush(); /** (try to) add transaction to memory pool **/ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, - bool* pfMissingInputs, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0); + bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0); /** Convert CValidationState to a human-readable message for logging */ std::string FormatStateMessage(const CValidationState &state); +/** Get the BIP9 state for a given deployment at the current tip. */ +ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos); + struct CNodeStateStats { int nMisbehavior; int nSyncHeight; @@ -369,6 +376,11 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime); bool CheckFinalTx(const CTransaction &tx, int flags = -1); /** + * Test whether the LockPoints height and time are still valid on the current chain + */ +bool TestLockPointValidity(const LockPoints* lp); + +/** * Check if transaction is final per BIP 68 sequence numbers and can be included in a block. * Consensus critical. Takes as input a list of heights at which tx's inputs (in order) confirmed. */ @@ -378,10 +390,14 @@ bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeig * Check if transaction will be BIP 68 final in the next block to be created. * * Simulates calling SequenceLocks() with data from the tip of the current active chain. + * Optionally stores in LockPoints the resulting height and time calculated and the hash + * of the block needed for calculation or skips the calculation and uses the LockPoints + * passed in for evaluation. + * The LockPoints should not be considered valid if CheckSequenceLocks returns false. * * See consensus/consensus.h for flag definitions. */ -bool CheckSequenceLocks(const CTransaction &tx, int flags); +bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = NULL, bool useExistingLockPoints = false); /** * Closure representing one script verification @@ -537,6 +553,11 @@ extern CBlockTreeDB *pblocktree; */ int GetSpendHeight(const CCoinsViewCache& inputs); +/** + * Determine what nVersion a new block should use. + */ +int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params); + /** Reject codes greater or equal to this can be returned by AcceptToMemPool * for transactions, to signal internal conditions. They cannot and should not * be sent over the P2P network. diff --git a/src/miner.cpp b/src/miner.cpp index c454c0279c..ef8fd4db43 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -79,11 +79,6 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s return NULL; CBlock *pblock = &pblocktemplate->block; // pointer for convenience - // -regtest only: allow overriding block.nVersion with - // -blockversion=N to test forking scenarios - if (chainparams.MineBlocksOnDemand()) - pblock->nVersion = GetArg("-blockversion", pblock->nVersion); - // Create coinbase tx CMutableTransaction txNew; txNew.vin.resize(1); @@ -137,6 +132,12 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s pblock->nTime = GetAdjustedTime(); const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); + pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); + // -regtest only: allow overriding block.nVersion with + // -blockversion=N to test forking scenarios + if (chainparams.MineBlocksOnDemand()) + pblock->nVersion = GetArg("-blockversion", pblock->nVersion); + int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) ? nMedianTimePast : pblock->GetBlockTime(); @@ -155,10 +156,10 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer); } - CTxMemPool::indexed_transaction_set::nth_index<3>::type::iterator mi = mempool.mapTx.get<3>().begin(); + CTxMemPool::indexed_transaction_set::index<mining_score>::type::iterator mi = mempool.mapTx.get<mining_score>().begin(); CTxMemPool::txiter iter; - while (mi != mempool.mapTx.get<3>().end() || !clearedTxs.empty()) + while (mi != mempool.mapTx.get<mining_score>().end() || !clearedTxs.empty()) { bool priorityTx = false; if (fPriorityBlock && !vecPriority.empty()) { // add a tx from priority queue to fill the blockprioritysize @@ -315,206 +316,3 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned pblock->vtx[0] = txCoinbase; pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); } - -////////////////////////////////////////////////////////////////////////////// -// -// Internal miner -// - -// -// ScanHash scans nonces looking for a hash with at least some zero bits. -// The nonce is usually preserved between calls, but periodically or if the -// nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at -// zero. -// -bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash) -{ - // Write the first 76 bytes of the block header to a double-SHA256 state. - CHash256 hasher; - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << *pblock; - assert(ss.size() == 80); - hasher.Write((unsigned char*)&ss[0], 76); - - while (true) { - nNonce++; - - // Write the last 4 bytes of the block header (the nonce) to a copy of - // the double-SHA256 state, and compute the result. - CHash256(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)phash); - - // Return the nonce if the hash has at least some zero bits, - // caller will check if it has enough to reach the target - if (((uint16_t*)phash)[15] == 0) - return true; - - // If nothing found after trying for a while, return -1 - if ((nNonce & 0xfff) == 0) - return false; - } -} - -static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams) -{ - LogPrintf("%s\n", pblock->ToString()); - LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue)); - - // Found a solution - { - LOCK(cs_main); - if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash()) - return error("BitcoinMiner: generated block is stale"); - } - - // Inform about the new block - GetMainSignals().BlockFound(pblock->GetHash()); - - // Process this block the same as if we had received it from another node - CValidationState state; - if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)) - return error("BitcoinMiner: ProcessNewBlock, block not accepted"); - - return true; -} - -void static BitcoinMiner(const CChainParams& chainparams) -{ - LogPrintf("BitcoinMiner started\n"); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - RenameThread("bitcoin-miner"); - - unsigned int nExtraNonce = 0; - - boost::shared_ptr<CReserveScript> coinbaseScript; - GetMainSignals().ScriptForMining(coinbaseScript); - - try { - // Throw an error if no script was provided. This can happen - // due to some internal error but also if the keypool is empty. - // In the latter case, already the pointer is NULL. - if (!coinbaseScript || coinbaseScript->reserveScript.empty()) - throw std::runtime_error("No coinbase script available (mining requires a wallet)"); - - while (true) { - if (chainparams.MiningRequiresPeers()) { - // Busy-wait for the network to come online so we don't waste time mining - // on an obsolete chain. In regtest mode we expect to fly solo. - do { - bool fvNodesEmpty; - { - LOCK(cs_vNodes); - fvNodesEmpty = vNodes.empty(); - } - if (!fvNodesEmpty && !IsInitialBlockDownload()) - break; - MilliSleep(1000); - } while (true); - } - - // - // Create new block - // - unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrev = chainActive.Tip(); - - auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(chainparams, coinbaseScript->reserveScript)); - if (!pblocktemplate.get()) - { - LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); - return; - } - CBlock *pblock = &pblocktemplate->block; - IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - - LogPrintf("Running BitcoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(), - ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); - - // - // Search - // - int64_t nStart = GetTime(); - arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); - uint256 hash; - uint32_t nNonce = 0; - while (true) { - // Check if something found - if (ScanHash(pblock, nNonce, &hash)) - { - if (UintToArith256(hash) <= hashTarget) - { - // Found a solution - pblock->nNonce = nNonce; - assert(hash == pblock->GetHash()); - - SetThreadPriority(THREAD_PRIORITY_NORMAL); - LogPrintf("BitcoinMiner:\n"); - LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex()); - ProcessBlockFound(pblock, chainparams); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - coinbaseScript->KeepScript(); - - // In regression test mode, stop mining after a block is found. - if (chainparams.MineBlocksOnDemand()) - throw boost::thread_interrupted(); - - break; - } - } - - // Check for stop or if block needs to be rebuilt - boost::this_thread::interruption_point(); - // Regtest mode doesn't require peers - if (vNodes.empty() && chainparams.MiningRequiresPeers()) - break; - if (nNonce >= 0xffff0000) - break; - if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) - break; - if (pindexPrev != chainActive.Tip()) - break; - - // Update nTime every few seconds - if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0) - break; // Recreate the block if the clock has run backwards, - // so that we can use the correct time. - if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) - { - // Changing pblock->nTime can change work required on testnet: - hashTarget.SetCompact(pblock->nBits); - } - } - } - } - catch (const boost::thread_interrupted&) - { - LogPrintf("BitcoinMiner terminated\n"); - throw; - } - catch (const std::runtime_error &e) - { - LogPrintf("BitcoinMiner runtime error: %s\n", e.what()); - return; - } -} - -void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams) -{ - static boost::thread_group* minerThreads = NULL; - - if (nThreads < 0) - nThreads = GetNumCores(); - - if (minerThreads != NULL) - { - minerThreads->interrupt_all(); - delete minerThreads; - minerThreads = NULL; - } - - if (nThreads == 0 || !fGenerate) - return; - - minerThreads = new boost::thread_group(); - for (int i = 0; i < nThreads; i++) - minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams))); -} diff --git a/src/miner.h b/src/miner.h index 512494198b..cd0f136625 100644 --- a/src/miner.h +++ b/src/miner.h @@ -17,9 +17,6 @@ class CScript; class CWallet; namespace Consensus { struct Params; }; -static const bool DEFAULT_GENERATE = false; -static const int DEFAULT_GENERATE_THREADS = 1; - static const bool DEFAULT_PRINTPRIORITY = false; struct CBlockTemplate @@ -29,8 +26,6 @@ struct CBlockTemplate std::vector<int64_t> vTxSigOps; }; -/** Run the miner threads */ -void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams); /** Generate a new block, without valid proof-of-work */ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn); /** Modify the extranonce in a block */ diff --git a/src/net.cpp b/src/net.cpp index e06e5255d6..e8cc753a48 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -79,7 +79,6 @@ bool fListen = true; uint64_t nLocalServices = NODE_NETWORK; CCriticalSection cs_mapLocalHost; map<CNetAddr, LocalServiceInfo> mapLocalHost; -static bool vfReachable[NET_MAX] = {}; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; uint64_t nLocalHostNonce = 0; @@ -226,14 +225,6 @@ void AdvertiseLocal(CNode *pnode) } } -void SetReachable(enum Network net, bool fFlag) -{ - LOCK(cs_mapLocalHost); - vfReachable[net] = fFlag; - if (net == NET_IPV6 && fFlag) - vfReachable[NET_IPV4] = true; -} - // learn a new local address bool AddLocal(const CService& addr, int nScore) { @@ -256,7 +247,6 @@ bool AddLocal(const CService& addr, int nScore) info.nScore = nScore + (fAlready ? 1 : 0); info.nPort = addr.GetPort(); } - SetReachable(addr.GetNetwork()); } return true; @@ -319,7 +309,7 @@ bool IsLocal(const CService& addr) bool IsReachable(enum Network net) { LOCK(cs_mapLocalHost); - return vfReachable[net] && !vfLimited[net]; + return !vfLimited[net]; } /** check whether a given address is in a network we can probably connect to */ @@ -2063,20 +2053,15 @@ public: instance_of_cnetcleanup; - - - - - -void RelayTransaction(const CTransaction& tx) +void RelayTransaction(const CTransaction& tx, CFeeRate feerate) { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(10000); ss << tx; - RelayTransaction(tx, ss); + RelayTransaction(tx, feerate, ss); } -void RelayTransaction(const CTransaction& tx, const CDataStream& ss) +void RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStream& ss) { CInv inv(MSG_TX, tx.GetHash()); { @@ -2097,6 +2082,11 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss) { if(!pnode->fRelayTxes) continue; + { + LOCK(pnode->cs_feeFilter); + if (feerate.GetFeePerK() < pnode->minFeeFilter) + continue; + } LOCK(pnode->cs_filter); if (pnode->pfilter) { @@ -2400,6 +2390,10 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nPingUsecTime = 0; fPingQueued = false; nMinPingUsecTime = std::numeric_limits<int64_t>::max(); + minFeeFilter = 0; + lastSentFeeFilter = 0; + nextSendTimeFeeFilter = 0; + BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; @@ -6,6 +6,7 @@ #ifndef BITCOIN_NET_H #define BITCOIN_NET_H +#include "amount.h" #include "bloom.h" #include "compat.h" #include "limitedmap.h" @@ -146,7 +147,6 @@ bool IsLocal(const CService& addr); bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL); bool IsReachable(enum Network net); bool IsReachable(const CNetAddr &addr); -void SetReachable(enum Network net, bool fFlag = true); CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); @@ -416,6 +416,11 @@ public: int64_t nMinPingUsecTime; // Whether a ping is requested. bool fPingQueued; + // Minimum fee rate with which to filter inv's to this node + CAmount minFeeFilter; + CCriticalSection cs_feeFilter; + CAmount lastSentFeeFilter; + int64_t nextSendTimeFeeFilter; CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false); ~CNode(); @@ -767,8 +772,8 @@ public: class CTransaction; -void RelayTransaction(const CTransaction& tx); -void RelayTransaction(const CTransaction& tx, const CDataStream& ss); +void RelayTransaction(const CTransaction& tx, CFeeRate feerate); +void RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStream& ss); /** Access to the (IP) address database (peers.dat) */ class CAddrDB diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index de3c060d6a..7b0e8b7d08 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -8,6 +8,7 @@ #include "amount.h" #include "primitives/transaction.h" +#include "random.h" #include "streams.h" #include "txmempool.h" #include "util.h" @@ -580,3 +581,21 @@ void CBlockPolicyEstimator::Read(CAutoFile& filein) priStats.Read(filein); nBestSeenHeight = nFileBestSeenHeight; } + +FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee) +{ + CAmount minFeeLimit = minIncrementalFee.GetFeePerK() / 2; + feeset.insert(0); + for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) { + feeset.insert(bucketBoundary); + } +} + +CAmount FeeFilterRounder::round(CAmount currentMinFee) +{ + std::set<double>::iterator it = feeset.lower_bound(currentMinFee); + if ((it != feeset.begin() && insecure_rand() % 3 != 0) || it == feeset.end()) { + it--; + } + return *it; +} diff --git a/src/policy/fees.h b/src/policy/fees.h index 3fa31c39e7..cdd984de7d 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -286,4 +286,17 @@ private: CFeeRate feeLikely, feeUnlikely; double priLikely, priUnlikely; }; + +class FeeFilterRounder +{ +public: + /** Create new FeeFilterRounder */ + FeeFilterRounder(const CFeeRate& minIncrementalFee); + + /** Quantize a minimum fee for privacy purpose before broadcast **/ + CAmount round(CAmount currentMinFee); + +private: + std::set<double> feeset; +}; #endif /*BITCOIN_POLICYESTIMATOR_H */ diff --git a/src/primitives/block.h b/src/primitives/block.h index 0e93399c08..42276b2bc2 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -21,7 +21,6 @@ class CBlockHeader { public: // header - static const int32_t CURRENT_VERSION=4; int32_t nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; @@ -49,7 +48,7 @@ public: void SetNull() { - nVersion = CBlockHeader::CURRENT_VERSION; + nVersion = 0; hashPrevBlock.SetNull(); hashMerkleRoot.SetNull(); nTime = 0; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 07ae39e0b4..e124dca365 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -34,7 +34,8 @@ public: friend bool operator<(const COutPoint& a, const COutPoint& b) { - return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n)); + int cmp = a.hash.Compare(b.hash); + return cmp < 0 || (cmp == 0 && a.n < b.n); } friend bool operator==(const COutPoint& a, const COutPoint& b) diff --git a/src/protocol.cpp b/src/protocol.cpp index c1c7c0b96b..8c4bd05725 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -28,13 +28,13 @@ const char *GETADDR="getaddr"; const char *MEMPOOL="mempool"; const char *PING="ping"; const char *PONG="pong"; -const char *ALERT="alert"; const char *NOTFOUND="notfound"; const char *FILTERLOAD="filterload"; const char *FILTERADD="filteradd"; const char *FILTERCLEAR="filterclear"; const char *REJECT="reject"; const char *SENDHEADERS="sendheaders"; +const char *FEEFILTER="feefilter"; }; static const char* ppszTypeName[] = @@ -64,13 +64,13 @@ const static std::string allNetMessageTypes[] = { NetMsgType::MEMPOOL, NetMsgType::PING, NetMsgType::PONG, - NetMsgType::ALERT, NetMsgType::NOTFOUND, NetMsgType::FILTERLOAD, NetMsgType::FILTERADD, NetMsgType::FILTERCLEAR, NetMsgType::REJECT, - NetMsgType::SENDHEADERS + NetMsgType::SENDHEADERS, + NetMsgType::FEEFILTER }; const static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes)); diff --git a/src/protocol.h b/src/protocol.h index c8b8d20ead..1b049e52af 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -164,13 +164,6 @@ extern const char *PING; */ extern const char *PONG; /** - * The alert message warns nodes of problems that may affect them or the rest - * of the network. - * @since protocol version 311. - * @see https://bitcoin.org/en/developer-reference#alert - */ -extern const char *ALERT; -/** * The notfound message is a reply to a getdata message which requested an * object the receiving node does not have available for relay. * @ince protocol version 70001. @@ -218,7 +211,12 @@ extern const char *REJECT; * @see https://bitcoin.org/en/developer-reference#sendheaders */ extern const char *SENDHEADERS; - +/** + * The feefilter message tells the receiving peer not to inv us any txs + * which do not meet the specified min fee rate. + * @since protocol version 70013 as described by BIP133 + */ +extern const char *FEEFILTER; }; /* Get a vector of all valid message types (see above) */ diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index fb502b3c81..d3edfedff2 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -8,7 +8,6 @@ #include "guiconstants.h" #include "peertablemodel.h" -#include "alert.h" #include "chainparams.h" #include "checkpoints.h" #include "clientversion.h" @@ -122,20 +121,8 @@ void ClientModel::updateNumConnections(int numConnections) Q_EMIT numConnectionsChanged(numConnections); } -void ClientModel::updateAlert(const QString &hash, int status) +void ClientModel::updateAlert() { - // Show error message notification for new alert - if(status == CT_NEW) - { - uint256 hash_256; - hash_256.SetHex(hash.toStdString()); - CAlert alert = CAlert::getAlertByHash(hash_256); - if(!alert.IsNull()) - { - Q_EMIT message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR); - } - } - Q_EMIT alertsChanged(getStatusBarWarnings()); } @@ -227,12 +214,10 @@ static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConn Q_ARG(int, newNumConnections)); } -static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status) +static void NotifyAlertChanged(ClientModel *clientmodel) { - qDebug() << "NotifyAlertChanged: " + QString::fromStdString(hash.GetHex()) + " status=" + QString::number(status); - QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(hash.GetHex())), - Q_ARG(int, status)); + qDebug() << "NotifyAlertChanged"; + QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection); } static void BannedListChanged(ClientModel *clientmodel) @@ -266,7 +251,7 @@ void ClientModel::subscribeToCoreSignals() // Connect signals to client uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1)); - uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2)); + uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this)); uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this)); uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2)); } @@ -276,7 +261,7 @@ void ClientModel::unsubscribeFromCoreSignals() // Disconnect signals from client uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1)); - uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2)); + uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this)); uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this)); uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2)); } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 62c9f71ac7..2fef6131c3 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -103,7 +103,7 @@ Q_SIGNALS: public Q_SLOTS: void updateTimer(); void updateNumConnections(int numConnections); - void updateAlert(const QString &hash, int status); + void updateAlert(); void updateBanlist(); }; diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index febbaeda1b..a5ac0a7d26 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>740</width> - <height>450</height> + <height>430</height> </rect> </property> <property name="windowTitle"> @@ -113,32 +113,6 @@ </widget> </item> <item row="4" column="0"> - <widget class="QLabel" name="label_14"> - <property name="text"> - <string>Using OpenSSL version</string> - </property> - <property name="indent"> - <number>10</number> - </property> - </widget> - </item> - <item row="4" column="1" colspan="2"> - <widget class="QLabel" name="openSSLVersion"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="5" column="0"> <widget class="QLabel" name="label_berkeleyDBVersion"> <property name="text"> <string>Using BerkeleyDB version</string> @@ -148,7 +122,7 @@ </property> </widget> </item> - <item row="5" column="1" colspan="2"> + <item row="4" column="1" colspan="2"> <widget class="QLabel" name="berkeleyDBVersion"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -164,14 +138,14 @@ </property> </widget> </item> - <item row="6" column="0"> + <item row="5" column="0"> <widget class="QLabel" name="label_12"> <property name="text"> <string>Build date</string> </property> </widget> </item> - <item row="6" column="1" colspan="2"> + <item row="5" column="1" colspan="2"> <widget class="QLabel" name="buildDate"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -187,14 +161,14 @@ </property> </widget> </item> - <item row="7" column="0"> + <item row="6" column="0"> <widget class="QLabel" name="label_13"> <property name="text"> <string>Startup time</string> </property> </widget> </item> - <item row="7" column="1" colspan="2"> + <item row="6" column="1" colspan="2"> <widget class="QLabel" name="startupTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -210,14 +184,27 @@ </property> </widget> </item> - <item row="9" column="0"> + <item row="7" column="0"> + <widget class="QLabel" name="labelNetwork"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Network</string> + </property> + </widget> + </item> + <item row="8" column="0"> <widget class="QLabel" name="label_8"> <property name="text"> <string>Name</string> </property> </widget> </item> - <item row="9" column="1" colspan="2"> + <item row="8" column="1" colspan="2"> <widget class="QLabel" name="networkName"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -233,14 +220,14 @@ </property> </widget> </item> - <item row="10" column="0"> + <item row="9" column="0"> <widget class="QLabel" name="label_7"> <property name="text"> <string>Number of connections</string> </property> </widget> </item> - <item row="10" column="1" colspan="2"> + <item row="9" column="1" colspan="2"> <widget class="QLabel" name="numberOfConnections"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -256,7 +243,7 @@ </property> </widget> </item> - <item row="11" column="0"> + <item row="10" column="0"> <widget class="QLabel" name="label_10"> <property name="font"> <font> @@ -269,14 +256,14 @@ </property> </widget> </item> - <item row="12" column="0"> + <item row="11" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Current number of blocks</string> </property> </widget> </item> - <item row="12" column="1" colspan="2"> + <item row="11" column="1" colspan="2"> <widget class="QLabel" name="numberOfBlocks"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -292,14 +279,14 @@ </property> </widget> </item> - <item row="13" column="0"> + <item row="12" column="0"> <widget class="QLabel" name="labelLastBlockTime"> <property name="text"> <string>Last block time</string> </property> </widget> </item> - <item row="13" column="1" colspan="2"> + <item row="12" column="1" colspan="2"> <widget class="QLabel" name="lastBlockTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -315,7 +302,7 @@ </property> </widget> </item> - <item row="14" column="0"> + <item row="13" column="0"> <widget class="QLabel" name="labelMempoolTitle"> <property name="font"> <font> @@ -328,14 +315,14 @@ </property> </widget> </item> - <item row="15" column="0"> + <item row="14" column="0"> <widget class="QLabel" name="labelNumberOfTransactions"> <property name="text"> <string>Current number of transactions</string> </property> </widget> </item> - <item row="15" column="1"> + <item row="14" column="1"> <widget class="QLabel" name="mempoolNumberTxs"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -351,27 +338,14 @@ </property> </widget> </item> - <item row="8" column="0"> - <widget class="QLabel" name="labelNetwork"> - <property name="font"> - <font> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string>Network</string> - </property> - </widget> - </item> - <item row="16" column="0"> + <item row="15" column="0"> <widget class="QLabel" name="labelMemoryUsage"> <property name="text"> <string>Memory usage</string> </property> </widget> </item> - <item row="16" column="1"> + <item row="15" column="1"> <widget class="QLabel" name="mempoolSize"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -387,7 +361,7 @@ </property> </widget> </item> - <item row="14" column="2" rowspan="3"> + <item row="13" column="2" rowspan="3"> <layout class="QVBoxLayout" name="verticalLayoutDebugButton"> <property name="spacing"> <number>3</number> @@ -427,7 +401,7 @@ </item> </layout> </item> - <item row="18" column="0"> + <item row="16" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 8911b41cbf..12d6a62c08 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -617,7 +617,7 @@ <x>0</x> <y>0</y> <width>830</width> - <height>68</height> + <height>104</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1"> @@ -1167,59 +1167,6 @@ </item> </layout> </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayoutFee5" stretch="0,0,0"> - <property name="spacing"> - <number>8</number> - </property> - <property name="bottomMargin"> - <number>4</number> - </property> - <item> - <widget class="QCheckBox" name="checkBoxFreeTx"> - <property name="text"> - <string>Send as zero-fee transaction if possible</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="labelFreeTx"> - <property name="text"> - <string>(confirmation may take longer)</string> - </property> - <property name="margin"> - <number>5</number> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacerFee5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>1</width> - <height>1</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item> - <spacer name="verticalSpacerFee2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>1</width> - <height>1</height> - </size> - </property> - </spacer> - </item> </layout> </widget> </item> diff --git a/src/qt/res/icons/about.png b/src/qt/res/icons/about.png Binary files differindex 83eb3c07ee..4143be8bac 100644 --- a/src/qt/res/icons/about.png +++ b/src/qt/res/icons/about.png diff --git a/src/qt/res/icons/chevron.png b/src/qt/res/icons/chevron.png Binary files differindex ac985052c1..2309fb38e2 100644 --- a/src/qt/res/icons/chevron.png +++ b/src/qt/res/icons/chevron.png diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index c18c405256..e8ee3042db 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -36,6 +36,7 @@ #include <QThread> #include <QTime> #include <QTimer> +#include <QStringList> #if QT_VERSION < 0x050000 #include <QUrl> @@ -275,13 +276,6 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) : connect(ui->btnClearTrafficGraph, SIGNAL(clicked()), ui->trafficGraph, SLOT(clear())); // set library version labels - -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) - ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION)); -#else - ui->openSSLVersion->setText(OpenSSL_version(OPENSSL_VERSION)); -#endif - #ifdef ENABLE_WALLET ui->berkeleyDBVersion->setText(DbEnv::version(0, 0, 0)); #else @@ -453,6 +447,18 @@ void RPCConsole::setClientModel(ClientModel *model) ui->buildDate->setText(model->formatBuildDate()); ui->startupTime->setText(model->formatClientStartupTime()); ui->networkName->setText(QString::fromStdString(Params().NetworkIDString())); + + //Setup autocomplete and attach it + QStringList wordList; + std::vector<std::string> commandList = tableRPC.listCommands(); + for (size_t i = 0; i < commandList.size(); ++i) + { + wordList << commandList[i].c_str(); + } + + autoCompleter = new QCompleter(wordList, this); + ui->lineEdit->setCompleter(autoCompleter); + } } @@ -497,16 +503,19 @@ void RPCConsole::setFontSize(int newSize) // clear console (reset icon sizes, default stylesheet) and re-add the content float oldPosFactor = 1.0 / ui->messagesWidget->verticalScrollBar()->maximum() * ui->messagesWidget->verticalScrollBar()->value(); - clear(); + clear(false); ui->messagesWidget->setHtml(str); ui->messagesWidget->verticalScrollBar()->setValue(oldPosFactor * ui->messagesWidget->verticalScrollBar()->maximum()); } -void RPCConsole::clear() +void RPCConsole::clear(bool clearHistory) { ui->messagesWidget->clear(); - history.clear(); - historyPtr = 0; + if(clearHistory) + { + history.clear(); + historyPtr = 0; + } ui->lineEdit->clear(); ui->lineEdit->setFocus(); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 648e32638f..2923587bc8 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -11,6 +11,7 @@ #include "net.h" #include <QWidget> +#include <QCompleter> class ClientModel; class PlatformStyle; @@ -77,7 +78,7 @@ private Q_SLOTS: void clearSelectedNode(); public Q_SLOTS: - void clear(); + void clear(bool clearHistory = true); void fontBigger(); void fontSmaller(); void setFontSize(int newSize); @@ -138,6 +139,7 @@ private: QMenu *peersTableContextMenu; QMenu *banTableContextMenu; int consoleFontSize; + QCompleter *autoCompleter; }; #endif // BITCOIN_QT_RPCCONSOLE_H diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 5fc7b57a41..780a6c9709 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -104,8 +104,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa settings.setValue("nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE); if (!settings.contains("fPayOnlyMinFee")) settings.setValue("fPayOnlyMinFee", false); - if (!settings.contains("fSendFreeTransactions")) - settings.setValue("fSendFreeTransactions", false); ui->groupFee->setId(ui->radioSmartFee, 0); ui->groupFee->setId(ui->radioCustomFee, 1); ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true); @@ -115,7 +113,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt()); ui->customFee->setValue(settings.value("nTransactionFee").toLongLong()); ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool()); - ui->checkBoxFreeTx->setChecked(settings.value("fSendFreeTransactions").toBool()); minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool()); } @@ -170,8 +167,6 @@ void SendCoinsDialog::setModel(WalletModel *model) connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); - connect(ui->checkBoxFreeTx, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables())); - connect(ui->checkBoxFreeTx, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000)); updateFeeSectionControls(); updateMinFeeLabel(); @@ -189,7 +184,6 @@ SendCoinsDialog::~SendCoinsDialog() settings.setValue("nSmartFeeSliderPosition", ui->sliderSmartFee->value()); settings.setValue("nTransactionFee", (qint64)ui->customFee->value()); settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked()); - settings.setValue("fSendFreeTransactions", ui->checkBoxFreeTx->isChecked()); delete ui; } @@ -605,8 +599,6 @@ void SendCoinsDialog::updateGlobalFeeVariables() // set nMinimumTotalFee to 0 in case of user has selected that the fee is per KB CoinControlDialog::coinControl->nMinimumTotalFee = ui->radioCustomAtLeast->isChecked() ? ui->customFee->value() : 0; } - - fSendFreeTransactions = ui->checkBoxFreeTx->isChecked(); } void SendCoinsDialog::updateFeeMinimizedLabel() diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 1647b2a6fe..d2a52b3022 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -609,6 +609,34 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const return QString::fromStdString(rec->hash.ToString()); case TxHexRole: return priv->getTxHex(rec); + case TxPlainTextRole: + { + QString details; + QDateTime date = QDateTime::fromTime_t(static_cast<uint>(rec->time)); + QString txLabel = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address)); + + details.append(date.toString("M/d/yy HH:mm")); + details.append(" "); + details.append(formatTxStatus(rec)); + details.append(". "); + if(!formatTxType(rec).isEmpty()) { + details.append(formatTxType(rec)); + details.append(" "); + } + if(!rec->address.empty()) { + if(txLabel.isEmpty()) + details.append(tr("(no label)") + " "); + else { + details.append("("); + details.append(txLabel); + details.append(") "); + } + details.append(QString::fromStdString(rec->address)); + details.append(" "); + } + details.append(formatTxAmount(rec, false, BitcoinUnits::separatorNever)); + return details; + } case ConfirmedRole: return rec->status.countsForBalance; case FormattedAmountRole: diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index fe59a15f6a..6932646e1e 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -62,6 +62,8 @@ public: TxHashRole, /** Transaction data, hex-encoded */ TxHexRole, + /** Whole transaction as plain text */ + TxPlainTextRole, /** Is transaction confirmed? */ ConfirmedRole, /** Formatted amount, without brackets when unconfirmed */ diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 4a9a198216..a4d4c7a35f 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -142,6 +142,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa QAction *copyAmountAction = new QAction(tr("Copy amount"), this); QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this); QAction *copyTxHexAction = new QAction(tr("Copy raw transaction"), this); + QAction *copyTxPlainText = new QAction(tr("Copy full transaction details"), this); QAction *editLabelAction = new QAction(tr("Edit label"), this); QAction *showDetailsAction = new QAction(tr("Show transaction details"), this); @@ -151,6 +152,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa contextMenu->addAction(copyAmountAction); contextMenu->addAction(copyTxIDAction); contextMenu->addAction(copyTxHexAction); + contextMenu->addAction(copyTxPlainText); contextMenu->addAction(editLabelAction); contextMenu->addAction(showDetailsAction); @@ -173,6 +175,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID())); connect(copyTxHexAction, SIGNAL(triggered()), this, SLOT(copyTxHex())); + connect(copyTxPlainText, SIGNAL(triggered()), this, SLOT(copyTxPlainText())); connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel())); connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails())); } @@ -388,6 +391,11 @@ void TransactionView::copyTxHex() GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxHexRole); } +void TransactionView::copyTxPlainText() +{ + GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxPlainTextRole); +} + void TransactionView::editLabel() { if(!transactionView->selectionModel() ||!model) @@ -526,12 +534,8 @@ bool TransactionView::eventFilter(QObject *obj, QEvent *event) QKeyEvent *ke = static_cast<QKeyEvent *>(event); if (ke->key() == Qt::Key_C && ke->modifiers().testFlag(Qt::ControlModifier)) { - QModelIndex i = this->transactionView->currentIndex(); - if (i.isValid() && i.column() == TransactionTableModel::Amount) - { - GUIUtil::setClipboard(i.data(TransactionTableModel::FormattedAmountRole).toString()); - return true; - } + GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxPlainTextRole); + return true; } } return QWidget::eventFilter(obj, event); diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index cf2b8fbcd4..2cfbd471b0 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -94,6 +94,7 @@ private Q_SLOTS: void copyAmount(); void copyTxID(); void copyTxHex(); + void copyTxPlainText(); void openThirdPartyTxUrl(QString url); void updateWatchOnlyColumn(bool fHaveWatchOnly); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index de6bda4ea1..a110dff0d1 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -89,7 +89,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { UniValue result(UniValue::VOBJ); - result.push_back(Pair("hash", block.GetHash().GetHex())); + result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) @@ -604,6 +604,20 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* return rv; } +static UniValue BIP9SoftForkDesc(const std::string& name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) +{ + UniValue rv(UniValue::VOBJ); + rv.push_back(Pair("id", name)); + switch (VersionBitsTipState(consensusParams, id)) { + case THRESHOLD_DEFINED: rv.push_back(Pair("status", "defined")); break; + case THRESHOLD_STARTED: rv.push_back(Pair("status", "started")); break; + case THRESHOLD_LOCKED_IN: rv.push_back(Pair("status", "locked_in")); break; + case THRESHOLD_ACTIVE: rv.push_back(Pair("status", "active")); break; + case THRESHOLD_FAILED: rv.push_back(Pair("status", "failed")); break; + } + return rv; +} + UniValue getblockchaininfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -634,6 +648,12 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) " },\n" " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n" " }, ...\n" + " ],\n" + " \"bip9_softforks\": [ (array) status of BIP9 softforks in progress\n" + " {\n" + " \"id\": \"xxxx\", (string) name of the softfork\n" + " \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"lockedin\", \"active\", \"failed\"\n" + " }\n" " ]\n" "}\n" "\nExamples:\n" @@ -657,10 +677,12 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) const Consensus::Params& consensusParams = Params().GetConsensus(); CBlockIndex* tip = chainActive.Tip(); UniValue softforks(UniValue::VARR); + UniValue bip9_softforks(UniValue::VARR); softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams)); softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams)); softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams)); obj.push_back(Pair("softforks", softforks)); + obj.push_back(Pair("bip9_softforks", bip9_softforks)); if (fPruneMode) { diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index b0e9b6f153..89420b93d7 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -27,9 +27,11 @@ static const CRPCConvertParam vRPCConvertParams[] = { "stop", 0 }, { "setmocktime", 0 }, { "getaddednodeinfo", 0 }, - { "setgenerate", 0 }, - { "setgenerate", 1 }, { "generate", 0 }, + { "generate", 1 }, + { "generatetoaddress", 0 }, + { "generatetoaddress", 1 }, + { "generatetoaddress", 2 }, { "getnetworkhashps", 0 }, { "getnetworkhashps", 1 }, { "sendtoaddress", 1 }, @@ -160,4 +162,3 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s return params; } - diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index fec0987a4c..a2abbb323d 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "base58.h" #include "amount.h" #include "chain.h" #include "chainparams.h" @@ -93,59 +94,12 @@ UniValue getnetworkhashps(const UniValue& params, bool fHelp) return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); } -UniValue getgenerate(const UniValue& params, bool fHelp) +UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript) { - if (fHelp || params.size() != 0) - throw runtime_error( - "getgenerate\n" - "\nReturn if the server is set to generate coins or not. The default is false.\n" - "It is set with the command line argument -gen (or " + std::string(BITCOIN_CONF_FILENAME) + " setting gen)\n" - "It can also be set with the setgenerate call.\n" - "\nResult\n" - "true|false (boolean) If the server is set to generate coins or not\n" - "\nExamples:\n" - + HelpExampleCli("getgenerate", "") - + HelpExampleRpc("getgenerate", "") - ); - - LOCK(cs_main); - return GetBoolArg("-gen", DEFAULT_GENERATE); -} - -UniValue generate(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 1) - throw runtime_error( - "generate numblocks\n" - "\nMine blocks immediately (before the RPC call returns)\n" - "\nNote: this function can only be used on the regtest network\n" - "\nArguments:\n" - "1. numblocks (numeric, required) How many blocks are generated immediately.\n" - "\nResult\n" - "[ blockhashes ] (array) hashes of blocks generated\n" - "\nExamples:\n" - "\nGenerate 11 blocks\n" - + HelpExampleCli("generate", "11") - ); - - if (!Params().MineBlocksOnDemand()) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); - + static const int nInnerLoopCount = 0x10000; int nHeightStart = 0; int nHeightEnd = 0; int nHeight = 0; - int nGenerate = params[0].get_int(); - - boost::shared_ptr<CReserveScript> coinbaseScript; - GetMainSignals().ScriptForMining(coinbaseScript); - - // If the keypool is exhausted, no script is returned at all. Catch this. - if (!coinbaseScript) - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - - //throw an error if no script was provided - if (coinbaseScript->reserveScript.empty()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); { // Don't keep cs_main locked LOCK(cs_main); @@ -165,10 +119,15 @@ UniValue generate(const UniValue& params, bool fHelp) LOCK(cs_main); IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); } - while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { - // Yes, there is a chance every nonce could fail to satisfy the -regtest - // target -- 1 in 2^(2^32). That ain't gonna happen. + while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount && !CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { ++pblock->nNonce; + --nMaxTries; + } + if (nMaxTries == 0) { + break; + } + if (pblock->nNonce == nInnerLoopCount) { + continue; } CValidationState state; if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) @@ -176,54 +135,82 @@ UniValue generate(const UniValue& params, bool fHelp) ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); - //mark script as important because it was used at least for one coinbase output - coinbaseScript->KeepScript(); + //mark script as important because it was used at least for one coinbase output if the script came from the wallet + if (keepScript) + { + coinbaseScript->KeepScript(); + } } return blockHashes; } -UniValue setgenerate(const UniValue& params, bool fHelp) +UniValue generate(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( - "setgenerate generate ( genproclimit )\n" - "\nSet 'generate' true or false to turn generation on or off.\n" - "Generation is limited to 'genproclimit' processors, -1 is unlimited.\n" - "See the getgenerate call for the current setting.\n" + "generate numblocks ( maxtries )\n" + "\nMine up to numblocks blocks immediately (before the RPC call returns)\n" "\nArguments:\n" - "1. generate (boolean, required) Set to true to turn on generation, off to turn off.\n" - "2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n" + "1. numblocks (numeric, required) How many blocks are generated immediately.\n" + "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n" + "\nResult\n" + "[ blockhashes ] (array) hashes of blocks generated\n" "\nExamples:\n" - "\nSet the generation on with a limit of one processor\n" - + HelpExampleCli("setgenerate", "true 1") + - "\nCheck the setting\n" - + HelpExampleCli("getgenerate", "") + - "\nTurn off generation\n" - + HelpExampleCli("setgenerate", "false") + - "\nUsing json rpc\n" - + HelpExampleRpc("setgenerate", "true, 1") + "\nGenerate 11 blocks\n" + + HelpExampleCli("generate", "11") ); - if (Params().MineBlocksOnDemand()) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network"); + int nGenerate = params[0].get_int(); + uint64_t nMaxTries = 1000000; + if (params.size() > 1) { + nMaxTries = params[1].get_int(); + } - bool fGenerate = true; - if (params.size() > 0) - fGenerate = params[0].get_bool(); + boost::shared_ptr<CReserveScript> coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); - int nGenProcLimit = GetArg("-genproclimit", DEFAULT_GENERATE_THREADS); - if (params.size() > 1) - { - nGenProcLimit = params[1].get_int(); - if (nGenProcLimit == 0) - fGenerate = false; + // If the keypool is exhausted, no script is returned at all. Catch this. + if (!coinbaseScript) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + + //throw an error if no script was provided + if (coinbaseScript->reserveScript.empty()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); + + return generateBlocks(coinbaseScript, nGenerate, nMaxTries, true); +} + +UniValue generatetoaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 3) + throw runtime_error( + "generatetoaddress numblocks address (maxtries)\n" + "\nMine blocks immediately to a specified address (before the RPC call returns)\n" + "\nArguments:\n" + "1. numblocks (numeric, required) How many blocks are generated immediately.\n" + "2. address (string, required) The address to send the newly generated bitcoin to.\n" + "3. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n" + "\nResult\n" + "[ blockhashes ] (array) hashes of blocks generated\n" + "\nExamples:\n" + "\nGenerate 11 blocks to myaddress\n" + + HelpExampleCli("generatetoaddress", "11 \"myaddress\"") + ); + + int nGenerate = params[0].get_int(); + uint64_t nMaxTries = 1000000; + if (params.size() > 2) { + nMaxTries = params[2].get_int(); } - mapArgs["-gen"] = (fGenerate ? "1" : "0"); - mapArgs ["-genproclimit"] = itostr(nGenProcLimit); - GenerateBitcoins(fGenerate, nGenProcLimit, Params()); + CBitcoinAddress address(params[1].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address"); + + boost::shared_ptr<CReserveScript> coinbaseScript(new CReserveScript()); + coinbaseScript->reserveScript = GetScriptForDestination(address.Get()); - return NullUniValue; + return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false); } UniValue getmininginfo(const UniValue& params, bool fHelp) @@ -239,8 +226,6 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) " \"currentblocktx\": nnn, (numeric) The last block transaction\n" " \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n" " \"errors\": \"...\" (string) Current errors\n" - " \"generate\": true|false (boolean) If the generation is on or off (see getgenerate or setgenerate calls)\n" - " \"genproclimit\": n (numeric) The processor limit for generation. -1 if no generation. (see getgenerate or setgenerate calls)\n" " \"pooledtx\": n (numeric) The size of the mem pool\n" " \"testnet\": true|false (boolean) If using testnet or not\n" " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" @@ -259,12 +244,10 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("errors", GetWarnings("statusbar"))); - obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", DEFAULT_GENERATE_THREADS))); obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); obj.push_back(Pair("chain", Params().NetworkIDString())); - obj.push_back(Pair("generate", getgenerate(params, false))); return obj; } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index de89fdeb0f..c72339313c 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -818,11 +818,12 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) const CCoins* existingCoins = view.AccessCoins(hashTx); bool fHaveMempool = mempool.exists(hashTx); bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000; + CFeeRate txFeeRate = CFeeRate(0); if (!fHaveMempool && !fHaveChain) { // push to local node and sync with wallets CValidationState state; bool fMissingInputs; - if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, nMaxRawTxFee)) { + if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, &txFeeRate, false, nMaxRawTxFee)) { if (state.IsInvalid()) { throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); } else { @@ -835,7 +836,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) } else if (fHaveChain) { throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); } - RelayTransaction(tx); + RelayTransaction(tx, txFeeRate); return hashTx.GetHex(); } diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index b2d4559ccd..1303a3bb13 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -298,9 +298,8 @@ static const CRPCCommand vRPCCommands[] = { "mining", "submitblock", &submitblock, true }, /* Coin generation */ - { "generating", "getgenerate", &getgenerate, true }, - { "generating", "setgenerate", &setgenerate, true }, { "generating", "generate", &generate, true }, + { "generating", "generatetoaddress", &generatetoaddress, true }, /* Raw transactions */ { "rawtransactions", "createrawtransaction", &createrawtransaction, true }, @@ -499,6 +498,17 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms g_rpcSignals.PostCommand(*pcmd); } +std::vector<std::string> CRPCTable::listCommands() const +{ + std::vector<std::string> commandList; + typedef std::map<std::string, const CRPCCommand*> commandMap; + + std::transform( mapCommands.begin(), mapCommands.end(), + std::back_inserter(commandList), + boost::bind(&commandMap::value_type::first,_1) ); + return commandList; +} + std::string HelpExampleCli(const std::string& methodname, const std::string& args) { return "> bitcoin-cli " + methodname + " " + args + "\n"; diff --git a/src/rpc/server.h b/src/rpc/server.h index 99ffad5d40..35e114feef 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -145,6 +145,12 @@ public: */ UniValue execute(const std::string &method, const UniValue ¶ms) const; + /** + * Returns a list of registered commands + * @returns List of registered commands. + */ + std::vector<std::string> listCommands() const; + /** * Appends a CRPCCommand to the dispatch table. @@ -186,9 +192,8 @@ extern UniValue setban(const UniValue& params, bool fHelp); extern UniValue listbanned(const UniValue& params, bool fHelp); extern UniValue clearbanned(const UniValue& params, bool fHelp); -extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpc/mining.cpp -extern UniValue setgenerate(const UniValue& params, bool fHelp); extern UniValue generate(const UniValue& params, bool fHelp); +extern UniValue generatetoaddress(const UniValue& params, bool fHelp); extern UniValue getnetworkhashps(const UniValue& params, bool fHelp); extern UniValue getmininginfo(const UniValue& params, bool fHelp); extern UniValue prioritisetransaction(const UniValue& params, bool fHelp); diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index 0895ef3326..70f1f12273 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -4,193 +4,16 @@ // Unit tests for alert system -#include "alert.h" -#include "chain.h" #include "chainparams.h" -#include "clientversion.h" -#include "data/alertTests.raw.h" #include "main.h" // For PartitionCheck -#include "serialize.h" -#include "streams.h" -#include "util.h" -#include "utilstrencodings.h" +#include "test/testutil.h" #include "test/test_bitcoin.h" -#include <fstream> - -#include <boost/filesystem/operations.hpp> -#include <boost/foreach.hpp> #include <boost/test/unit_test.hpp> -#if 0 -// -// alertTests contains 7 alerts, generated with this code: -// (SignAndSave code not shown, alert signing key is secret) -// -{ - CAlert alert; - alert.nRelayUntil = 60; - alert.nExpiration = 24 * 60 * 60; - alert.nID = 1; - alert.nCancel = 0; // cancels previous messages up to this ID number - alert.nMinVer = 0; // These versions are protocol versions - alert.nMaxVer = 999001; - alert.nPriority = 1; - alert.strComment = "Alert comment"; - alert.strStatusBar = "Alert 1"; - - SignAndSave(alert, "test/alertTests"); - - alert.setSubVer.insert(std::string("/Satoshi:0.1.0/")); - alert.strStatusBar = "Alert 1 for Satoshi 0.1.0"; - SignAndSave(alert, "test/alertTests"); - - alert.setSubVer.insert(std::string("/Satoshi:0.2.0/")); - alert.strStatusBar = "Alert 1 for Satoshi 0.1.0, 0.2.0"; - SignAndSave(alert, "test/alertTests"); - - alert.setSubVer.clear(); - ++alert.nID; - alert.nCancel = 1; - alert.nPriority = 100; - alert.strStatusBar = "Alert 2, cancels 1"; - SignAndSave(alert, "test/alertTests"); - - alert.nExpiration += 60; - ++alert.nID; - SignAndSave(alert, "test/alertTests"); - - ++alert.nID; - alert.nMinVer = 11; - alert.nMaxVer = 22; - SignAndSave(alert, "test/alertTests"); - - ++alert.nID; - alert.strStatusBar = "Alert 2 for Satoshi 0.1.0"; - alert.setSubVer.insert(std::string("/Satoshi:0.1.0/")); - SignAndSave(alert, "test/alertTests"); - - ++alert.nID; - alert.nMinVer = 0; - alert.nMaxVer = 999999; - alert.strStatusBar = "Evil Alert'; /bin/ls; echo '"; - alert.setSubVer.clear(); - SignAndSave(alert, "test/alertTests"); -} -#endif - -struct ReadAlerts : public TestingSetup -{ - ReadAlerts() - { - std::vector<unsigned char> vch(alert_tests::alertTests, alert_tests::alertTests + sizeof(alert_tests::alertTests)); - CDataStream stream(vch, SER_DISK, CLIENT_VERSION); - try { - while (!stream.eof()) - { - CAlert alert; - stream >> alert; - alerts.push_back(alert); - } - } - catch (const std::exception&) { } - } - ~ReadAlerts() { } - - static std::vector<std::string> read_lines(boost::filesystem::path filepath) - { - std::vector<std::string> result; - - std::ifstream f(filepath.string().c_str()); - std::string line; - while (std::getline(f,line)) - result.push_back(line); - - return result; - } - - std::vector<CAlert> alerts; -}; - -BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts) - - -BOOST_AUTO_TEST_CASE(AlertApplies) -{ - SetMockTime(11); - const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey(); +BOOST_FIXTURE_TEST_SUITE(Alert_tests, TestingSetup) - BOOST_FOREACH(const CAlert& alert, alerts) - { - BOOST_CHECK(alert.CheckSignature(alertKey)); - } - - BOOST_CHECK(alerts.size() >= 3); - - // Matches: - BOOST_CHECK(alerts[0].AppliesTo(1, "")); - BOOST_CHECK(alerts[0].AppliesTo(999001, "")); - BOOST_CHECK(alerts[0].AppliesTo(1, "/Satoshi:11.11.11/")); - - BOOST_CHECK(alerts[1].AppliesTo(1, "/Satoshi:0.1.0/")); - BOOST_CHECK(alerts[1].AppliesTo(999001, "/Satoshi:0.1.0/")); - - BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.1.0/")); - BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.2.0/")); - - // Don't match: - BOOST_CHECK(!alerts[0].AppliesTo(-1, "")); - BOOST_CHECK(!alerts[0].AppliesTo(999002, "")); - - BOOST_CHECK(!alerts[1].AppliesTo(1, "")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.1.0")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0/")); - BOOST_CHECK(!alerts[1].AppliesTo(-1, "/Satoshi:0.1.0/")); - BOOST_CHECK(!alerts[1].AppliesTo(999002, "/Satoshi:0.1.0/")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.2.0/")); - - BOOST_CHECK(!alerts[2].AppliesTo(1, "/Satoshi:0.3.0/")); - - SetMockTime(0); -} - - -BOOST_AUTO_TEST_CASE(AlertNotify) -{ - SetMockTime(11); - const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey(); - - boost::filesystem::path temp = GetTempPath() / - boost::filesystem::unique_path("alertnotify-%%%%.txt"); - - mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string(); - - BOOST_FOREACH(CAlert alert, alerts) - alert.ProcessAlert(alertKey, false); - - std::vector<std::string> r = read_lines(temp); - BOOST_CHECK_EQUAL(r.size(), 4u); - -// Windows built-in echo semantics are different than posixy shells. Quotes and -// whitespace are printed literally. - -#ifndef WIN32 - BOOST_CHECK_EQUAL(r[0], "Alert 1"); - BOOST_CHECK_EQUAL(r[1], "Alert 2, cancels 1"); - BOOST_CHECK_EQUAL(r[2], "Alert 2, cancels 1"); - BOOST_CHECK_EQUAL(r[3], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed -#else - BOOST_CHECK_EQUAL(r[0], "'Alert 1' "); - BOOST_CHECK_EQUAL(r[1], "'Alert 2, cancels 1' "); - BOOST_CHECK_EQUAL(r[2], "'Alert 2, cancels 1' "); - BOOST_CHECK_EQUAL(r[3], "'Evil Alert; /bin/ls; echo ' "); -#endif - boost::filesystem::remove(temp); - - SetMockTime(0); -} static bool falseFunc() { return false; } @@ -253,4 +76,4 @@ BOOST_AUTO_TEST_CASE(PartitionAlert) SetMockTime(0); } -BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp new file mode 100644 index 0000000000..59dab20633 --- /dev/null +++ b/src/test/amount_tests.cpp @@ -0,0 +1,42 @@ +// Copyright (c) 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. + +#include "amount.h" +#include "test/test_bitcoin.h" + +#include <boost/test/unit_test.hpp> + +BOOST_FIXTURE_TEST_SUITE(amount_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(GetFeeTest) +{ + CFeeRate feeRate; + + feeRate = CFeeRate(0); + // Must always return 0 + BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); + BOOST_CHECK_EQUAL(feeRate.GetFee(1e5), 0); + + feeRate = CFeeRate(1000); + // Must always just return the arg + BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); + BOOST_CHECK_EQUAL(feeRate.GetFee(1), 1); + BOOST_CHECK_EQUAL(feeRate.GetFee(121), 121); + BOOST_CHECK_EQUAL(feeRate.GetFee(999), 999); + BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 1e3); + BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 9e3); + + feeRate = CFeeRate(123); + // Truncates the result, if not integer + BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); + BOOST_CHECK_EQUAL(feeRate.GetFee(8), 1); // Special case: returns 1 instead of 0 + BOOST_CHECK_EQUAL(feeRate.GetFee(9), 1); + BOOST_CHECK_EQUAL(feeRate.GetFee(121), 14); + BOOST_CHECK_EQUAL(feeRate.GetFee(122), 15); + BOOST_CHECK_EQUAL(feeRate.GetFee(999), 122); + BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 123); + BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 1107); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/data/alertTests.raw b/src/test/data/alertTests.raw Binary files differdeleted file mode 100644 index 01f50680b9..0000000000 --- a/src/test/data/alertTests.raw +++ /dev/null diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json index 7ce7e0879c..9e91132984 100644 --- a/src/test/data/script_invalid.json +++ b/src/test/data/script_invalid.json @@ -6,504 +6,519 @@ ["correct prevout hash), using the given scriptSig. All nLockTimes are 0, all"], ["nSequences are max."], -["", "DEPTH", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"], -[" ", "DEPTH", "P2SH,STRICTENC", "and multiple spaces should not change that."], -[" ", "DEPTH", "P2SH,STRICTENC"], -[" ", "DEPTH", "P2SH,STRICTENC"], - -["", "", "P2SH,STRICTENC"], -["", "NOP", "P2SH,STRICTENC"], -["", "NOP DEPTH", "P2SH,STRICTENC"], -["NOP", "", "P2SH,STRICTENC"], -["NOP", "DEPTH", "P2SH,STRICTENC"], -["NOP","NOP", "P2SH,STRICTENC"], -["NOP","NOP DEPTH", "P2SH,STRICTENC"], - -["DEPTH", "", "P2SH,STRICTENC"], - -["0x4c01","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA1 with not enough bytes"], -["0x4d0200ff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA2 with not enough bytes"], -["0x4e03000000ffff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA4 with not enough bytes"], - -["1", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved"], -["0x52", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack"], -["0","NOP", "P2SH,STRICTENC"], -["1", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "VER non-functional"], -["0", "IF VERIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere"], -["0", "IF ELSE 1 ELSE VERIF ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere"], -["0", "IF VERNOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere"], -["0", "IF ELSE 1 ELSE VERNOTIF ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere"], - -["1 IF", "1 ENDIF", "P2SH,STRICTENC", "IF/ENDIF can't span scriptSig/scriptPubKey"], -["1 IF 0 ENDIF", "1 ENDIF", "P2SH,STRICTENC"], -["1 ELSE 0 ENDIF", "1", "P2SH,STRICTENC"], -["0 NOTIF", "123", "P2SH,STRICTENC"], - -["0", "DUP IF ENDIF", "P2SH,STRICTENC"], -["0", "IF 1 ENDIF", "P2SH,STRICTENC"], -["0", "DUP IF ELSE ENDIF", "P2SH,STRICTENC"], -["0", "IF 1 ELSE ENDIF", "P2SH,STRICTENC"], -["0", "NOTIF ELSE 1 ENDIF", "P2SH,STRICTENC"], - -["0 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], - -["0 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], - -["1", "IF RETURN ELSE ELSE 1 ENDIF", "P2SH,STRICTENC", "Multiple ELSEs"], -["1", "IF 1 ELSE ELSE RETURN ENDIF", "P2SH,STRICTENC"], - -["1", "ENDIF", "P2SH,STRICTENC", "Malformed IF/ELSE/ENDIF sequence"], -["1", "ELSE ENDIF", "P2SH,STRICTENC"], -["1", "ENDIF ELSE", "P2SH,STRICTENC"], -["1", "ENDIF ELSE IF", "P2SH,STRICTENC"], -["1", "IF ELSE ENDIF ELSE", "P2SH,STRICTENC"], -["1", "IF ELSE ENDIF ELSE ENDIF", "P2SH,STRICTENC"], -["1", "IF ENDIF ENDIF", "P2SH,STRICTENC"], -["1", "IF ELSE ELSE ENDIF ENDIF", "P2SH,STRICTENC"], - -["1", "RETURN", "P2SH,STRICTENC"], -["1", "DUP IF RETURN ENDIF", "P2SH,STRICTENC"], - -["1", "RETURN 'data'", "P2SH,STRICTENC", "canonical prunable txout format"], -["0 IF", "RETURN ENDIF 1", "P2SH,STRICTENC", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey"], - -["0", "VERIFY 1", "P2SH,STRICTENC"], -["1", "VERIFY", "P2SH,STRICTENC"], -["1", "VERIFY 0", "P2SH,STRICTENC"], - -["1 TOALTSTACK", "FROMALTSTACK 1", "P2SH,STRICTENC", "alt stack not shared between sig/pubkey"], - -["IFDUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["DUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["1", "DUP 1 ADD 2 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], -["NOP", "NIP", "P2SH,STRICTENC"], -["NOP", "1 NIP", "P2SH,STRICTENC"], -["NOP", "1 0 NIP", "P2SH,STRICTENC"], -["NOP", "OVER 1", "P2SH,STRICTENC"], -["1", "OVER", "P2SH,STRICTENC"], -["0 1", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC"], -["19 20 21", "PICK 19 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["NOP", "0 PICK", "P2SH,STRICTENC"], -["1", "-1 PICK", "P2SH,STRICTENC"], -["19 20 21", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["19 20 21", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["19 20 21", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["NOP", "0 ROLL", "P2SH,STRICTENC"], -["1", "-1 ROLL", "P2SH,STRICTENC"], -["19 20 21", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["19 20 21", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["19 20 21", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["NOP", "ROT 1", "P2SH,STRICTENC"], -["NOP", "1 ROT 1", "P2SH,STRICTENC"], -["NOP", "1 2 ROT 1", "P2SH,STRICTENC"], -["NOP", "0 1 2 ROT", "P2SH,STRICTENC"], -["NOP", "SWAP 1", "P2SH,STRICTENC"], -["1", "SWAP 1", "P2SH,STRICTENC"], -["0 1", "SWAP 1 EQUALVERIFY", "P2SH,STRICTENC"], -["NOP", "TUCK 1", "P2SH,STRICTENC"], -["1", "TUCK 1", "P2SH,STRICTENC"], -["1 0", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC"], -["NOP", "2DUP 1", "P2SH,STRICTENC"], -["1", "2DUP 1", "P2SH,STRICTENC"], -["NOP", "3DUP 1", "P2SH,STRICTENC"], -["1", "3DUP 1", "P2SH,STRICTENC"], -["1 2", "3DUP 1", "P2SH,STRICTENC"], -["NOP", "2OVER 1", "P2SH,STRICTENC"], -["1", "2 3 2OVER 1", "P2SH,STRICTENC"], -["NOP", "2SWAP 1", "P2SH,STRICTENC"], -["1", "2 3 2SWAP 1", "P2SH,STRICTENC"], - -["'a' 'b'", "CAT", "P2SH,STRICTENC", "CAT disabled"], -["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "P2SH,STRICTENC", "CAT disabled"], -["'abc' 1 1", "SUBSTR", "P2SH,STRICTENC", "SUBSTR disabled"], -["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "P2SH,STRICTENC", "SUBSTR disabled"], -["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "P2SH,STRICTENC", "LEFT disabled"], -["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "P2SH,STRICTENC", "RIGHT disabled"], - -["NOP", "SIZE 1", "P2SH,STRICTENC"], - -["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "INVERT disabled"], -["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "AND disabled"], -["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "OR disabled"], -["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "XOR disabled"], -["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2MUL disabled"], -["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2DIV disabled"], -["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MUL disabled"], -["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DIV disabled"], -["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MOD disabled"], -["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "LSHIFT disabled"], -["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "RSHIFT disabled"], - -["", "EQUAL NOT", "P2SH,STRICTENC", "EQUAL must error when there are no stack items"], -["0", "EQUAL NOT", "P2SH,STRICTENC", "EQUAL must error when there are not 2 stack items"], -["0 1","EQUAL", "P2SH,STRICTENC"], -["1 1 ADD", "0 EQUAL", "P2SH,STRICTENC"], -["11 1 ADD 12 SUB", "11 EQUAL", "P2SH,STRICTENC"], - -["2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] "], -["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] "], -["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "NUMEQUAL must be in numeric range"], -["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "NOT is an arithmetic operand"], - -["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 2DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled"], -["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "disabled"], - -["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC"], -["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC"], +["", "DEPTH", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation", "EVAL_FALSE"], +[" ", "DEPTH", "P2SH,STRICTENC", "and multiple spaces should not change that.", "EVAL_FALSE"], +[" ", "DEPTH", "P2SH,STRICTENC", "", "EVAL_FALSE"], +[" ", "DEPTH", "P2SH,STRICTENC", "", "EVAL_FALSE"], + +["", "", "P2SH,STRICTENC","", "EVAL_FALSE"], +["", "NOP", "P2SH,STRICTENC","", "EVAL_FALSE"], +["", "NOP DEPTH", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["NOP", "", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["NOP", "DEPTH", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["NOP","NOP", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["NOP","NOP DEPTH", "P2SH,STRICTENC", "", "EVAL_FALSE"], + +["DEPTH", "", "P2SH,STRICTENC", "", "EVAL_FALSE"], + +["0x4c01","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA1 with not enough bytes","BAD_OPCODE"], +["0x4d0200ff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA2 with not enough bytes","BAD_OPCODE"], +["0x4e03000000ffff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA4 with not enough bytes","BAD_OPCODE"], + +["1", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved","BAD_OPCODE"], +["0x52", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack","EVAL_FALSE"], +["0","NOP", "P2SH,STRICTENC","","EVAL_FALSE"], +["1", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "VER non-functional", "BAD_OPCODE"], +["0", "IF VERIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere", "BAD_OPCODE"], +["0", "IF ELSE 1 ELSE VERIF ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere", "BAD_OPCODE"], +["0", "IF VERNOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere", "BAD_OPCODE"], +["0", "IF ELSE 1 ELSE VERNOTIF ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere", "BAD_OPCODE"], + +["1 IF", "1 ENDIF", "P2SH,STRICTENC", "IF/ENDIF can't span scriptSig/scriptPubKey", "UNBALANCED_CONDITIONAL"], +["1 IF 0 ENDIF", "1 ENDIF", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"], +["1 ELSE 0 ENDIF", "1", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"], +["0 NOTIF", "123", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"], + +["0", "DUP IF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["0", "IF 1 ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["0", "DUP IF ELSE ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["0", "IF 1 ELSE ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["0", "NOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], + +["0 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["0 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["1 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["0 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], + +["0 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["0 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["1 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["0 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"], + +["1", "IF RETURN ELSE ELSE 1 ENDIF", "P2SH,STRICTENC", "Multiple ELSEs", "OP_RETURN"], +["1", "IF 1 ELSE ELSE RETURN ENDIF", "P2SH,STRICTENC", "", "OP_RETURN"], + +["1", "ENDIF", "P2SH,STRICTENC", "Malformed IF/ELSE/ENDIF sequence", "UNBALANCED_CONDITIONAL"], +["1", "ELSE ENDIF", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"], +["1", "ENDIF ELSE", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"], +["1", "ENDIF ELSE IF", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"], +["1", "IF ELSE ENDIF ELSE", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"], +["1", "IF ELSE ENDIF ELSE ENDIF", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"], +["1", "IF ENDIF ENDIF", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"], +["1", "IF ELSE ELSE ENDIF ENDIF", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"], + +["1", "RETURN", "P2SH,STRICTENC", "", "OP_RETURN"], +["1", "DUP IF RETURN ENDIF", "P2SH,STRICTENC", "", "OP_RETURN"], + +["1", "RETURN 'data'", "P2SH,STRICTENC", "canonical prunable txout format", "OP_RETURN"], +["0 IF", "RETURN ENDIF 1", "P2SH,STRICTENC", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey", "UNBALANCED_CONDITIONAL"], + +["0", "VERIFY 1", "P2SH,STRICTENC", "", "VERIFY"], +["1", "VERIFY", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["1", "VERIFY 0", "P2SH,STRICTENC", "", "EVAL_FALSE"], + +["1 TOALTSTACK", "FROMALTSTACK 1", "P2SH,STRICTENC", "alt stack not shared between sig/pubkey", "INVALID_ALTSTACK_OPERATION"], + +["IFDUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["DUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "DUP 1 ADD 2 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["NOP", "NIP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "1 NIP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "1 0 NIP", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["NOP", "OVER 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "OVER", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["0 1", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["19 20 21", "PICK 19 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "0 PICK", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "-1 PICK", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["19 20 21", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "", "EQUALVERIFY"], +["19 20 21", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "", "EQUALVERIFY"], +["19 20 21", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "", "EQUALVERIFY"], +["NOP", "0 ROLL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "-1 ROLL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["19 20 21", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "", "EQUALVERIFY"], +["19 20 21", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "", "EQUALVERIFY"], +["19 20 21", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "", "EQUALVERIFY"], +["NOP", "ROT 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "1 ROT 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "1 2 ROT 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "0 1 2 ROT", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["NOP", "SWAP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "SWAP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["0 1", "SWAP 1 EQUALVERIFY", "P2SH,STRICTENC", "", "EQUALVERIFY"], +["NOP", "TUCK 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "TUCK 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1 0", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["NOP", "2DUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "2DUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "3DUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "3DUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1 2", "3DUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "2OVER 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "2 3 2OVER 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "2SWAP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "2 3 2SWAP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], + +["'a' 'b'", "CAT", "P2SH,STRICTENC", "CAT disabled", "DISABLED_OPCODE"], +["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "P2SH,STRICTENC", "CAT disabled", "DISABLED_OPCODE"], +["'abc' 1 1", "SUBSTR", "P2SH,STRICTENC", "SUBSTR disabled", "DISABLED_OPCODE"], +["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "P2SH,STRICTENC", "SUBSTR disabled", "DISABLED_OPCODE"], +["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "P2SH,STRICTENC", "LEFT disabled", "DISABLED_OPCODE"], +["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "P2SH,STRICTENC", "RIGHT disabled", "DISABLED_OPCODE"], + +["NOP", "SIZE 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], + +["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "INVERT disabled", "DISABLED_OPCODE"], +["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "AND disabled", "DISABLED_OPCODE"], +["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "OR disabled", "DISABLED_OPCODE"], +["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "XOR disabled", "DISABLED_OPCODE"], +["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2MUL disabled", "DISABLED_OPCODE"], +["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2DIV disabled", "DISABLED_OPCODE"], +["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MUL disabled", "DISABLED_OPCODE"], +["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DIV disabled", "DISABLED_OPCODE"], +["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MOD disabled", "DISABLED_OPCODE"], +["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "LSHIFT disabled", "DISABLED_OPCODE"], +["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "RSHIFT disabled", "DISABLED_OPCODE"], + +["", "EQUAL NOT", "P2SH,STRICTENC", "EQUAL must error when there are no stack items", "INVALID_STACK_OPERATION"], +["0", "EQUAL NOT", "P2SH,STRICTENC", "EQUAL must error when there are not 2 stack items", "INVALID_STACK_OPERATION"], +["0 1","EQUAL", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["1 1 ADD", "0 EQUAL", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["11 1 ADD 12 SUB", "11 EQUAL", "P2SH,STRICTENC", "", "EVAL_FALSE"], + +["2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] ", "UNKNOWN_ERROR"], +["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] ", "UNKNOWN_ERROR"], +["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "NUMEQUAL must be in numeric range", "UNKNOWN_ERROR"], +["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "NOT is an arithmetic operand", "UNKNOWN_ERROR"], + +["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"], +["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"], +["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"], +["2 2DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"], +["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"], +["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"], +["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"], + +["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "", "EVAL_FALSE"], +["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "", "EVAL_FALSE"], ["Ensure 100% coverage of discouraged NOPS"], -["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "CHECKLOCKTIMEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP3", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP6", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP7", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP8", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP9", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP10", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], - -["NOP10", "1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in scriptSig"], +["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "CHECKLOCKTIMEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP3", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP6", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP7", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP8", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP9", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP10", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"], + +["NOP10", "1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in scriptSig", "DISCOURAGE_UPGRADABLE_NOPS"], ["1 0x01 0xb9", "HASH160 0x14 0x15727299b05b45fdaf9ac9ecf7565cfe27c3e567 EQUAL", - "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript"], - -["0x50","1", "P2SH,STRICTENC", "opcode 0x50 is reserved"], -["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "opcodes above NOP10 invalid if executed"], -["1", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC"], - -["1 IF 1 ELSE", "0xff ENDIF", "P2SH,STRICTENC", "invalid because scriptSig and scriptPubKey are processed separately"], - -["NOP", "RIPEMD160", "P2SH,STRICTENC"], -["NOP", "SHA1", "P2SH,STRICTENC"], -["NOP", "SHA256", "P2SH,STRICTENC"], -["NOP", "HASH160", "P2SH,STRICTENC"], -["NOP", "HASH256", "P2SH,STRICTENC"], + "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript", "DISCOURAGE_UPGRADABLE_NOPS"], + +["0x50","1", "P2SH,STRICTENC", "opcode 0x50 is reserved", "BAD_OPCODE"], +["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "opcodes above NOP10 invalid if executed", "BAD_OPCODE"], +["1", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], +["1", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"], + +["1 IF 1 ELSE", "0xff ENDIF", "P2SH,STRICTENC", "invalid because scriptSig and scriptPubKey are processed separately", "UNBALANCED_CONDITIONAL"], + +["NOP", "RIPEMD160", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "SHA1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "SHA256", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "HASH160", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "HASH256", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], ["NOP", "'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", "P2SH,STRICTENC", -">520 byte push"], +">520 byte push", +"PUSH_SIZE"], ["0", "IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1", "P2SH,STRICTENC", -">520 byte push in non-executed IF branch"], +">520 byte push in non-executed IF branch", +"PUSH_SIZE"], ["1", "0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", "P2SH,STRICTENC", -">201 opcodes executed. 0x61 is NOP"], +">201 opcodes executed. 0x61 is NOP", +"OP_COUNT"], ["0", "IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1", "P2SH,STRICTENC", -">201 opcodes including non-executed IF branch. 0x61 is NOP"], +">201 opcodes including non-executed IF branch. 0x61 is NOP", +"OP_COUNT"], ["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", "1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", "P2SH,STRICTENC", -">1,000 stack size (0x6f is 3DUP)"], +">1,000 stack size (0x6f is 3DUP)", +"STACK_SIZE"], ["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", "1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", "P2SH,STRICTENC", -">1,000 stack+altstack size"], +">1,000 stack+altstack size", +"STACK_SIZE"], ["NOP", "0 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", "P2SH,STRICTENC", -"10,001-byte scriptPubKey"], - -["NOP1","NOP10", "P2SH,STRICTENC"], - -["1","VER", "P2SH,STRICTENC", "OP_VER is reserved"], -["1","VERIF", "P2SH,STRICTENC", "OP_VERIF is reserved"], -["1","VERNOTIF", "P2SH,STRICTENC", "OP_VERNOTIF is reserved"], -["1","RESERVED", "P2SH,STRICTENC", "OP_RESERVED is reserved"], -["1","RESERVED1", "P2SH,STRICTENC", "OP_RESERVED1 is reserved"], -["1","RESERVED2", "P2SH,STRICTENC", "OP_RESERVED2 is reserved"], -["1","0xba", "P2SH,STRICTENC", "0xba == OP_NOP10 + 1"], - -["2147483648", "1ADD 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers"], -["2147483648", "NEGATE 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers"], -["-2147483648", "1ADD 1", "P2SH,STRICTENC", "Because we use a sign bit, -2147483648 is also 5 bytes"], -["2147483647", "1ADD 1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], -["2147483648", "1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], - -["2147483648 1", "BOOLOR 1", "P2SH,STRICTENC", "We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)"], -["2147483648 1", "BOOLAND 1", "P2SH,STRICTENC", "We cannot do BOOLAND on 5-byte integers"], - -["1", "1 ENDIF", "P2SH,STRICTENC", "ENDIF without IF"], -["1", "IF 1", "P2SH,STRICTENC", "IF without ENDIF"], -["1 IF 1", "ENDIF", "P2SH,STRICTENC", "IFs don't carry over"], - -["NOP", "IF 1 ENDIF", "P2SH,STRICTENC", "The following tests check the if(stack.size() < N) tests in each opcode"], -["NOP", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "They are here to catch copy-and-paste errors"], -["NOP", "VERIFY 1", "P2SH,STRICTENC", "Most of them are duplicated elsewhere,"], - -["NOP", "TOALTSTACK 1", "P2SH,STRICTENC", "but, hey, more is always better, right?"], -["1", "FROMALTSTACK", "P2SH,STRICTENC"], -["1", "2DROP 1", "P2SH,STRICTENC"], -["1", "2DUP", "P2SH,STRICTENC"], -["1 1", "3DUP", "P2SH,STRICTENC"], -["1 1 1", "2OVER", "P2SH,STRICTENC"], -["1 1 1 1 1", "2ROT", "P2SH,STRICTENC"], -["1 1 1", "2SWAP", "P2SH,STRICTENC"], -["NOP", "IFDUP 1", "P2SH,STRICTENC"], -["NOP", "DROP 1", "P2SH,STRICTENC"], -["NOP", "DUP 1", "P2SH,STRICTENC"], -["1", "NIP", "P2SH,STRICTENC"], -["1", "OVER", "P2SH,STRICTENC"], -["1 1 1 3", "PICK", "P2SH,STRICTENC"], -["0", "PICK 1", "P2SH,STRICTENC"], -["1 1 1 3", "ROLL", "P2SH,STRICTENC"], -["0", "ROLL 1", "P2SH,STRICTENC"], -["1 1", "ROT", "P2SH,STRICTENC"], -["1", "SWAP", "P2SH,STRICTENC"], -["1", "TUCK", "P2SH,STRICTENC"], - -["NOP", "SIZE 1", "P2SH,STRICTENC"], - -["1", "EQUAL 1", "P2SH,STRICTENC"], -["1", "EQUALVERIFY 1", "P2SH,STRICTENC"], - -["NOP", "1ADD 1", "P2SH,STRICTENC"], -["NOP", "1SUB 1", "P2SH,STRICTENC"], -["NOP", "NEGATE 1", "P2SH,STRICTENC"], -["NOP", "ABS 1", "P2SH,STRICTENC"], -["NOP", "NOT 1", "P2SH,STRICTENC"], -["NOP", "0NOTEQUAL 1", "P2SH,STRICTENC"], - -["1", "ADD", "P2SH,STRICTENC"], -["1", "SUB", "P2SH,STRICTENC"], -["1", "BOOLAND", "P2SH,STRICTENC"], -["1", "BOOLOR", "P2SH,STRICTENC"], -["1", "NUMEQUAL", "P2SH,STRICTENC"], -["1", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"], -["1", "NUMNOTEQUAL", "P2SH,STRICTENC"], -["1", "LESSTHAN", "P2SH,STRICTENC"], -["1", "GREATERTHAN", "P2SH,STRICTENC"], -["1", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["1", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], -["1", "MIN", "P2SH,STRICTENC"], -["1", "MAX", "P2SH,STRICTENC"], -["1 1", "WITHIN", "P2SH,STRICTENC"], - -["NOP", "RIPEMD160 1", "P2SH,STRICTENC"], -["NOP", "SHA1 1", "P2SH,STRICTENC"], -["NOP", "SHA256 1", "P2SH,STRICTENC"], -["NOP", "HASH160 1", "P2SH,STRICTENC"], -["NOP", "HASH256 1", "P2SH,STRICTENC"], +"10,001-byte scriptPubKey", +"SCRIPT_SIZE"], + +["NOP1","NOP10", "P2SH,STRICTENC", "", "EVAL_FALSE"], + +["1","VER", "P2SH,STRICTENC", "OP_VER is reserved", "BAD_OPCODE"], +["1","VERIF", "P2SH,STRICTENC", "OP_VERIF is reserved", "BAD_OPCODE"], +["1","VERNOTIF", "P2SH,STRICTENC", "OP_VERNOTIF is reserved", "BAD_OPCODE"], +["1","RESERVED", "P2SH,STRICTENC", "OP_RESERVED is reserved", "BAD_OPCODE"], +["1","RESERVED1", "P2SH,STRICTENC", "OP_RESERVED1 is reserved", "BAD_OPCODE"], +["1","RESERVED2", "P2SH,STRICTENC", "OP_RESERVED2 is reserved", "BAD_OPCODE"], +["1","0xba", "P2SH,STRICTENC", "0xba == OP_NOP10 + 1", "BAD_OPCODE"], + +["2147483648", "1ADD 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers", "UNKNOWN_ERROR"], +["2147483648", "NEGATE 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers", "UNKNOWN_ERROR"], +["-2147483648", "1ADD 1", "P2SH,STRICTENC", "Because we use a sign bit, -2147483648 is also 5 bytes", "UNKNOWN_ERROR"], +["2147483647", "1ADD 1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes", "UNKNOWN_ERROR"], +["2147483648", "1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes", "UNKNOWN_ERROR"], + +["2147483648 1", "BOOLOR 1", "P2SH,STRICTENC", "We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)", "UNKNOWN_ERROR"], +["2147483648 1", "BOOLAND 1", "P2SH,STRICTENC", "We cannot do BOOLAND on 5-byte integers", "UNKNOWN_ERROR"], + +["1", "1 ENDIF", "P2SH,STRICTENC", "ENDIF without IF", "UNBALANCED_CONDITIONAL"], +["1", "IF 1", "P2SH,STRICTENC", "IF without ENDIF", "UNBALANCED_CONDITIONAL"], +["1 IF 1", "ENDIF", "P2SH,STRICTENC", "IFs don't carry over", "UNBALANCED_CONDITIONAL"], + +["NOP", "IF 1 ENDIF", "P2SH,STRICTENC", "The following tests check the if(stack.size() < N) tests in each opcode", "UNBALANCED_CONDITIONAL"], +["NOP", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "They are here to catch copy-and-paste errors", "UNBALANCED_CONDITIONAL"], +["NOP", "VERIFY 1", "P2SH,STRICTENC", "Most of them are duplicated elsewhere,", "INVALID_STACK_OPERATION"], + +["NOP", "TOALTSTACK 1", "P2SH,STRICTENC", "but, hey, more is always better, right?", "INVALID_STACK_OPERATION"], +["1", "FROMALTSTACK", "P2SH,STRICTENC", "", "INVALID_ALTSTACK_OPERATION"], +["1", "2DROP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "2DUP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1 1", "3DUP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1 1 1", "2OVER", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1 1 1 1 1", "2ROT", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1 1 1", "2SWAP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "IFDUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "DROP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "DUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "NIP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "OVER", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1 1 1 3", "PICK", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["0", "PICK 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1 1 1 3", "ROLL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["0", "ROLL 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1 1", "ROT", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "SWAP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "TUCK", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], + +["NOP", "SIZE 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], + +["1", "EQUAL 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "EQUALVERIFY 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], + +["NOP", "1ADD 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "1SUB 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "NEGATE 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "ABS 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "NOT 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "0NOTEQUAL 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], + +["1", "ADD", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "SUB", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "BOOLAND", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "BOOLOR", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "NUMEQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "NUMEQUALVERIFY 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "NUMNOTEQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "LESSTHAN", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "GREATERTHAN", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "LESSTHANOREQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "GREATERTHANOREQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "MIN", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1", "MAX", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["1 1", "WITHIN", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], + +["NOP", "RIPEMD160 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "SHA1 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "SHA256 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "HASH160 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], +["NOP", "HASH256 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"], ["Increase CHECKSIG and CHECKMULTISIG negative test coverage"], -["", "CHECKSIG NOT", "STRICTENC", "CHECKSIG must error when there are no stack items"], -["0", "CHECKSIG NOT", "STRICTENC", "CHECKSIG must error when there are not 2 stack items"], -["", "CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are no stack items"], -["", "-1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when the specified number of pubkeys is negative"], -["", "1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are not enough pubkeys on the stack"], -["", "-1 0 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when the specified number of signatures is negative"], -["", "1 'pk1' 1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are not enough signatures on the stack"], -["", "'dummy' 'sig1' 1 'pk1' 1 CHECKMULTISIG IF 1 ENDIF", "", "CHECKMULTISIG must push false to stack when signature is invalid when NOT in strict enc mode"], +["", "CHECKSIG NOT", "STRICTENC", "CHECKSIG must error when there are no stack items", "INVALID_STACK_OPERATION"], +["0", "CHECKSIG NOT", "STRICTENC", "CHECKSIG must error when there are not 2 stack items", "INVALID_STACK_OPERATION"], +["", "CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are no stack items", "INVALID_STACK_OPERATION"], +["", "-1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when the specified number of pubkeys is negative", "PUBKEY_COUNT"], +["", "1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are not enough pubkeys on the stack", "INVALID_STACK_OPERATION"], +["", "-1 0 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when the specified number of signatures is negative", "SIG_COUNT"], +["", "1 'pk1' 1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are not enough signatures on the stack", "INVALID_STACK_OPERATION"], +["", "'dummy' 'sig1' 1 'pk1' 1 CHECKMULTISIG IF 1 ENDIF", "", "CHECKMULTISIG must push false to stack when signature is invalid when NOT in strict enc mode","EVAL_FALSE"], ["", "0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG", "P2SH,STRICTENC", -"202 CHECKMULTISIGS, fails due to 201 op limit"], +"202 CHECKMULTISIGS, fails due to 201 op limit", +"OP_COUNT"], ["1", "0 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY", -"P2SH,STRICTENC"], +"P2SH,STRICTENC", +"", +"INVALID_STACK_OPERATION"], ["", "NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG", "P2SH,STRICTENC", -"Fails due to 201 sig op limit"], +"Fails due to 201 sig op limit", +"OP_COUNT"], ["1", "NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY", -"P2SH,STRICTENC"], +"P2SH,STRICTENC", +"", +"OP_COUNT"], -["0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21", "21 CHECKMULTISIG 1", "P2SH,STRICTENC", "nPubKeys > 20"], -["0 'sig' 1 0", "CHECKMULTISIG 1", "P2SH,STRICTENC", "nSigs > nPubKeys"], +["0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21", "21 CHECKMULTISIG 1", "P2SH,STRICTENC", "nPubKeys > 20", "PUBKEY_COUNT"], +["0 'sig' 1 0", "CHECKMULTISIG 1", "P2SH,STRICTENC", "nSigs > nPubKeys", "SIG_COUNT"], -["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "Tests for Script.IsPushOnly()"], -["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC"], +["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "Tests for Script.IsPushOnly()", "SIG_PUSHONLY"], +["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "", "SIG_PUSHONLY"], -["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "P2SH,STRICTENC", "OP_RESERVED in P2SH should fail"], -["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "P2SH,STRICTENC", "OP_VER in P2SH should fail"], +["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "P2SH,STRICTENC", "OP_RESERVED in P2SH should fail", "BAD_OPCODE"], +["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "P2SH,STRICTENC", "OP_VER in P2SH should fail", "BAD_OPCODE"], -["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"], +["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution", "EVAL_FALSE"], ["MINIMALDATA enforcement for PUSHDATAs"], -["0x4c 0x00", "DROP 1", "MINIMALDATA", "Empty vector minimally represented by OP_0"], -["0x01 0x81", "DROP 1", "MINIMALDATA", "-1 minimally represented by OP_1NEGATE"], -["0x01 0x01", "DROP 1", "MINIMALDATA", "1 to 16 minimally represented by OP_1 to OP_16"], -["0x01 0x02", "DROP 1", "MINIMALDATA"], -["0x01 0x03", "DROP 1", "MINIMALDATA"], -["0x01 0x04", "DROP 1", "MINIMALDATA"], -["0x01 0x05", "DROP 1", "MINIMALDATA"], -["0x01 0x06", "DROP 1", "MINIMALDATA"], -["0x01 0x07", "DROP 1", "MINIMALDATA"], -["0x01 0x08", "DROP 1", "MINIMALDATA"], -["0x01 0x09", "DROP 1", "MINIMALDATA"], -["0x01 0x0a", "DROP 1", "MINIMALDATA"], -["0x01 0x0b", "DROP 1", "MINIMALDATA"], -["0x01 0x0c", "DROP 1", "MINIMALDATA"], -["0x01 0x0d", "DROP 1", "MINIMALDATA"], -["0x01 0x0e", "DROP 1", "MINIMALDATA"], -["0x01 0x0f", "DROP 1", "MINIMALDATA"], -["0x01 0x10", "DROP 1", "MINIMALDATA"], +["0x4c 0x00", "DROP 1", "MINIMALDATA", "Empty vector minimally represented by OP_0", "MINIMALDATA"], +["0x01 0x81", "DROP 1", "MINIMALDATA", "-1 minimally represented by OP_1NEGATE", "MINIMALDATA"], +["0x01 0x01", "DROP 1", "MINIMALDATA", "1 to 16 minimally represented by OP_1 to OP_16", "MINIMALDATA"], +["0x01 0x02", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x03", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x04", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x05", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x06", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x07", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x08", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x09", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x0a", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x0b", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x0c", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x0d", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x0e", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x0f", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], +["0x01 0x10", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"], ["0x4c 0x48 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", - "PUSHDATA1 of 72 bytes minimally represented by direct push"], + "PUSHDATA1 of 72 bytes minimally represented by direct push", + "MINIMALDATA"], ["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", - "PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1"], + "PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1", + "MINIMALDATA"], ["0x4e 0x00010000 0x11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", - "PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2"], - + "PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2", + "MINIMALDATA"], ["MINIMALDATA enforcement for numeric arguments"], -["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "numequals 0"], -["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "numequals 0"], -["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "0x80 (negative zero) numequals 0"], -["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "numequals 0"], -["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "numequals 5"], -["0x03 0x050000", "NOT DROP 1", "MINIMALDATA", "numequals 5"], -["0x02 0x0580", "NOT DROP 1", "MINIMALDATA", "numequals -5"], -["0x03 0x050080", "NOT DROP 1", "MINIMALDATA", "numequals -5"], -["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff"], -["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xff7f"], -["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffffff"], -["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff7f"], +["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "numequals 0", "UNKNOWN_ERROR"], +["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "numequals 0", "UNKNOWN_ERROR"], +["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "0x80 (negative zero) numequals 0", "UNKNOWN_ERROR"], +["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "numequals 0", "UNKNOWN_ERROR"], +["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "numequals 5", "UNKNOWN_ERROR"], +["0x03 0x050000", "NOT DROP 1", "MINIMALDATA", "numequals 5", "UNKNOWN_ERROR"], +["0x02 0x0580", "NOT DROP 1", "MINIMALDATA", "numequals -5", "UNKNOWN_ERROR"], +["0x03 0x050080", "NOT DROP 1", "MINIMALDATA", "numequals -5", "UNKNOWN_ERROR"], +["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff", "UNKNOWN_ERROR"], +["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xff7f", "UNKNOWN_ERROR"], +["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffffff", "UNKNOWN_ERROR"], +["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff7f", "UNKNOWN_ERROR"], ["Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule"], -["1 0x02 0x0000", "PICK DROP", "MINIMALDATA"], -["1 0x02 0x0000", "ROLL DROP 1", "MINIMALDATA"], -["0x02 0x0000", "1ADD DROP 1", "MINIMALDATA"], -["0x02 0x0000", "1SUB DROP 1", "MINIMALDATA"], -["0x02 0x0000", "NEGATE DROP 1", "MINIMALDATA"], -["0x02 0x0000", "ABS DROP 1", "MINIMALDATA"], -["0x02 0x0000", "NOT DROP 1", "MINIMALDATA"], -["0x02 0x0000", "0NOTEQUAL DROP 1", "MINIMALDATA"], - -["0 0x02 0x0000", "ADD DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "ADD DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "SUB DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "SUB DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "BOOLAND DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "BOOLAND DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "BOOLOR DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "BOOLOR DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "NUMEQUAL DROP 1", "MINIMALDATA"], -["0x02 0x0000 1", "NUMEQUAL DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "NUMEQUALVERIFY 1", "MINIMALDATA"], -["0x02 0x0000 0", "NUMEQUALVERIFY 1", "MINIMALDATA"], -["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "LESSTHAN DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "LESSTHAN DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "GREATERTHAN DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "GREATERTHAN DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "MIN DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "MIN DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "MAX DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "MAX DROP 1", "MINIMALDATA"], - -["0x02 0x0000 0 0", "WITHIN DROP 1", "MINIMALDATA"], -["0 0x02 0x0000 0", "WITHIN DROP 1", "MINIMALDATA"], -["0 0 0x02 0x0000", "WITHIN DROP 1", "MINIMALDATA"], - -["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "MINIMALDATA"], -["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "MINIMALDATA"], -["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "MINIMALDATA"], -["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"], -["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"], +["1 0x02 0x0000", "PICK DROP", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["1 0x02 0x0000", "ROLL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000", "1ADD DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000", "1SUB DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000", "NEGATE DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000", "ABS DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000", "0NOTEQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], + +["0 0x02 0x0000", "ADD DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "ADD DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "SUB DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "SUB DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "BOOLAND DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "BOOLAND DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "BOOLOR DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "BOOLOR DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "NUMEQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 1", "NUMEQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "NUMEQUALVERIFY 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "NUMEQUALVERIFY 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "LESSTHAN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "LESSTHAN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "GREATERTHAN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "GREATERTHAN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "MIN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "MIN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "MAX DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "MAX DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], + +["0x02 0x0000 0 0", "WITHIN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000 0", "WITHIN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0 0x02 0x0000", "WITHIN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], + +["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], +["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "MINIMALDATA", "", "UNKNOWN_ERROR"], ["Order of CHECKMULTISIG evaluation tests, inverted by swapping the order of"], @@ -513,301 +528,349 @@ "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501", "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0 2 CHECKMULTISIG NOT", "STRICTENC", - "2-of-2 CHECKMULTISIG NOT with the first pubkey invalid, and both signatures validly encoded." + "2-of-2 CHECKMULTISIG NOT with the first pubkey invalid, and both signatures validly encoded.", + "PUBKEYTYPE" ], [ "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 1", "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT", "STRICTENC", - "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid." + "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid.", + "SIG_DER" +], +[ + "0 0x47 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f01 0x46 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f", + "2 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 3 CHECKMULTISIG", + "P2SH,STRICTENC", + "2-of-3 with one valid and one invalid signature due to parse error, nSigs > validSigs", + "SIG_DER" ], ["Increase DERSIG test coverage"], -["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Overly long signature is incorrectly encoded for DERSIG"], -["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Missing S is incorrectly encoded for DERSIG"], -["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "S with invalid S length is incorrectly encoded for DERSIG"], -["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer R is incorrectly encoded for DERSIG"], -["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer S is incorrectly encoded for DERSIG"], -["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Zero-length R is incorrectly encoded for DERSIG"], -["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "DERSIG", "Zero-length S is incorrectly encoded for DERSIG"], -["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Negative S is incorrectly encoded for DERSIG"], +["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Overly long signature is incorrectly encoded for DERSIG", "SIG_DER"], +["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Missing S is incorrectly encoded for DERSIG", "SIG_DER"], +["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "S with invalid S length is incorrectly encoded for DERSIG", "SIG_DER"], +["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer R is incorrectly encoded for DERSIG", "SIG_DER"], +["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer S is incorrectly encoded for DERSIG", "SIG_DER"], +["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Zero-length R is incorrectly encoded for DERSIG", "SIG_DER"], +["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "DERSIG", "Zero-length S is incorrectly encoded for DERSIG", "SIG_DER"], +["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Negative S is incorrectly encoded for DERSIG", "SIG_DER"], ["Automatically generated test cases"], [ "0x47 0x304402200a5c6163f07b8c3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", - "P2PK, bad sig" + "P2PK, bad sig", + "EVAL_FALSE" ], [ "0x47 0x3044022034bb0494b50b8ef130e2185bb220265b9284ef5b4b8a8da4d8415df489c83b5102206259a26d9cc0a125ac26af6153b17c02956855ebe1467412f066e402f5f05d1201 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG", "", - "P2PKH, bad pubkey" + "P2PKH, bad pubkey", + "EQUALVERIFY" ], [ "0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790201", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", - "P2PK anyonecanpay marked with normal hashtype" + "P2PK anyonecanpay marked with normal hashtype", + "EVAL_FALSE" ], [ "0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", "P2SH", - "P2SH(P2PK), bad redeemscript" + "P2SH(P2PK), bad redeemscript", + "EVAL_FALSE" ], [ "0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", "P2SH", - "P2SH(P2PKH), bad sig" + "P2SH(P2PKH), bad sig", + "EQUALVERIFY" ], [ "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", - "3-of-3, 2 sigs" + "3-of-3, 2 sigs", + "EVAL_FALSE" ], [ "0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", "P2SH", - "P2SH(2-of-3), 1 sig" + "P2SH(2-of-3), 1 sig", + "EVAL_FALSE" ], [ "0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "DERSIG", - "P2PK with too much R padding" + "P2PK with too much R padding", + "SIG_DER" ], [ "0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "DERSIG", - "P2PK with too much S padding" + "P2PK with too much S padding", + "SIG_DER" ], [ "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "DERSIG", - "P2PK with too little R padding" + "P2PK with too little R padding", + "SIG_DER" ], [ "0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", "DERSIG", - "P2PK NOT with bad sig with too much R padding" + "P2PK NOT with bad sig with too much R padding", + "SIG_DER" ], [ "0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", "", - "P2PK NOT with too much R padding but no DERSIG" + "P2PK NOT with too much R padding but no DERSIG", + "EVAL_FALSE" ], [ "0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", "DERSIG", - "P2PK NOT with too much R padding" + "P2PK NOT with too much R padding", + "SIG_DER" ], [ "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "DERSIG", - "BIP66 example 1, with DERSIG" + "BIP66 example 1, with DERSIG", + "SIG_DER" ], [ "0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", "", - "BIP66 example 2, without DERSIG" + "BIP66 example 2, without DERSIG", + "EVAL_FALSE" ], [ "0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", "DERSIG", - "BIP66 example 2, with DERSIG" + "BIP66 example 2, with DERSIG", + "SIG_DER" ], [ "0", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "", - "BIP66 example 3, without DERSIG" + "BIP66 example 3, without DERSIG", + "EVAL_FALSE" ], [ "0", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "DERSIG", - "BIP66 example 3, with DERSIG" + "BIP66 example 3, with DERSIG", + "EVAL_FALSE" ], [ "1", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "", - "BIP66 example 5, without DERSIG" + "BIP66 example 5, without DERSIG", + "EVAL_FALSE" ], [ "1", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "DERSIG", - "BIP66 example 5, with DERSIG" + "BIP66 example 5, with DERSIG", + "SIG_DER" ], [ "1", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", "DERSIG", - "BIP66 example 6, with DERSIG" + "BIP66 example 6, with DERSIG", + "SIG_DER" ], [ "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", "DERSIG", - "BIP66 example 7, with DERSIG" + "BIP66 example 7, with DERSIG", + "SIG_DER" ], [ "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", "", - "BIP66 example 8, without DERSIG" + "BIP66 example 8, without DERSIG", + "EVAL_FALSE" ], [ "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", "DERSIG", - "BIP66 example 8, with DERSIG" + "BIP66 example 8, with DERSIG", + "SIG_DER" ], [ "0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", "", - "BIP66 example 9, without DERSIG" + "BIP66 example 9, without DERSIG", + "EVAL_FALSE" ], [ "0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", "DERSIG", - "BIP66 example 9, with DERSIG" + "BIP66 example 9, with DERSIG", + "SIG_DER" ], [ "0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", "DERSIG", - "BIP66 example 10, with DERSIG" + "BIP66 example 10, with DERSIG", + "SIG_DER" ], [ "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", "", - "BIP66 example 11, without DERSIG" + "BIP66 example 11, without DERSIG", + "EVAL_FALSE" ], [ "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", "DERSIG", - "BIP66 example 11, with DERSIG" + "BIP66 example 11, with DERSIG", + "EVAL_FALSE" ], [ "0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "DERSIG", - "P2PK with multi-byte hashtype, with DERSIG" + "P2PK with multi-byte hashtype, with DERSIG", + "SIG_DER" ], [ "0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "LOW_S", - "P2PK with high S" + "P2PK with high S", + "SIG_HIGH_S" ], [ "0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "STRICTENC", - "P2PK with hybrid pubkey" + "P2PK with hybrid pubkey", + "PUBKEYTYPE" ], [ "0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", "", - "P2PK NOT with hybrid pubkey but no STRICTENC" + "P2PK NOT with hybrid pubkey but no STRICTENC", + "EVAL_FALSE" ], [ "0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", "STRICTENC", - "P2PK NOT with hybrid pubkey" + "P2PK NOT with hybrid pubkey", + "PUBKEYTYPE" ], [ "0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", "STRICTENC", - "P2PK NOT with invalid hybrid pubkey" + "P2PK NOT with invalid hybrid pubkey", + "PUBKEYTYPE" ], [ "0 0x47 0x3044022079c7824d6c868e0e1a273484e28c2654a27d043c8a27f49f52cb72efed0759090220452bbbf7089574fa082095a4fc1b3a16bafcf97a3a34d745fafc922cce66b27201", "1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG", "STRICTENC", - "1-of-2 with the first 1 hybrid pubkey" + "1-of-2 with the first 1 hybrid pubkey", + "PUBKEYTYPE" ], [ "0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "STRICTENC", - "P2PK with undefined hashtype" + "P2PK with undefined hashtype", + "SIG_HASHTYPE" ], [ "0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT", "STRICTENC", - "P2PK NOT with invalid sig and undefined hashtype" + "P2PK NOT with invalid sig and undefined hashtype", + "SIG_HASHTYPE" ], [ "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "NULLDUMMY", - "3-of-3 with nonzero dummy" + "3-of-3 with nonzero dummy", + "SIG_NULLDUMMY" ], [ "1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT", "NULLDUMMY", - "3-of-3 NOT with invalid sig with nonzero dummy" + "3-of-3 NOT with invalid sig with nonzero dummy", + "SIG_NULLDUMMY" ], [ "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", "SIGPUSHONLY", - "2-of-2 with two identical keys and sigs pushed using OP_DUP" + "2-of-2 with two identical keys and sigs pushed using OP_DUP", + "SIG_PUSHONLY" ], [ "0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "", - "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY" + "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", + "EVAL_FALSE" ], [ "0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "SIGPUSHONLY", - "P2SH(P2PK) with non-push scriptSig" -], -[ - "0 0x47 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f01 0x46 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f", - "2 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 3 CHECKMULTISIG", - "P2SH,STRICTENC", - "2-of-3 with one valid and one invalid signature due to parse error, nSigs > validSigs" + "P2SH(P2PK) with non-push scriptSig", + "EVAL_FALSE" ], [ "11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "CLEANSTACK,P2SH", - "P2PK with unnecessary input" + "P2PK with unnecessary input", + "CLEANSTACK" ], [ "11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", "CLEANSTACK,P2SH", - "P2SH with unnecessary input" + "P2SH with unnecessary input", + "CLEANSTACK" ], ["The End"] diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 1347d23656..c8b43df26c 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -57,12 +57,12 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) std::list<CTransaction> removed; // Nothing in pool, remove should do nothing: - testPool.remove(txParent, removed, true); + testPool.removeRecursive(txParent, removed); BOOST_CHECK_EQUAL(removed.size(), 0); // Just the parent: testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); - testPool.remove(txParent, removed, true); + testPool.removeRecursive(txParent, removed); BOOST_CHECK_EQUAL(removed.size(), 1); removed.clear(); @@ -74,16 +74,16 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); } // Remove Child[0], GrandChild[0] should be removed: - testPool.remove(txChild[0], removed, true); + testPool.removeRecursive(txChild[0], removed); BOOST_CHECK_EQUAL(removed.size(), 2); removed.clear(); // ... make sure grandchild and child are gone: - testPool.remove(txGrandChild[0], removed, true); + testPool.removeRecursive(txGrandChild[0], removed); BOOST_CHECK_EQUAL(removed.size(), 0); - testPool.remove(txChild[0], removed, true); + testPool.removeRecursive(txChild[0], removed); BOOST_CHECK_EQUAL(removed.size(), 0); // Remove parent, all children/grandchildren should go: - testPool.remove(txParent, removed, true); + testPool.removeRecursive(txParent, removed); BOOST_CHECK_EQUAL(removed.size(), 5); BOOST_CHECK_EQUAL(testPool.size(), 0); removed.clear(); @@ -96,19 +96,19 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) } // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be // put into the mempool (maybe because it is non-standard): - testPool.remove(txParent, removed, true); + testPool.removeRecursive(txParent, removed); BOOST_CHECK_EQUAL(removed.size(), 6); BOOST_CHECK_EQUAL(testPool.size(), 0); removed.clear(); } -template<int index> +template<typename name> void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder) { BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size()); - typename CTxMemPool::indexed_transaction_set::nth_index<index>::type::iterator it = pool.mapTx.get<index>().begin(); + typename CTxMemPool::indexed_transaction_set::index<name>::type::iterator it = pool.mapTx.get<name>().begin(); int count=0; - for (; it != pool.mapTx.get<index>().end(); ++it, ++count) { + for (; it != pool.mapTx.get<name>().end(); ++it, ++count) { BOOST_CHECK_EQUAL(it->GetTx().GetHash().ToString(), sortedOrder[count]); } } @@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) sortedOrder[2] = tx1.GetHash().ToString(); // 10000 sortedOrder[3] = tx4.GetHash().ToString(); // 15000 sortedOrder[4] = tx2.GetHash().ToString(); // 20000 - CheckSort<1>(pool, sortedOrder); + CheckSort<descendant_score>(pool, sortedOrder); /* low fee but with high fee child */ /* tx6 -> tx7 -> tx8, tx9 -> tx10 */ @@ -176,7 +176,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) BOOST_CHECK_EQUAL(pool.size(), 6); // Check that at this point, tx6 is sorted low sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString()); - CheckSort<1>(pool, sortedOrder); + CheckSort<descendant_score>(pool, sortedOrder); CTxMemPool::setEntries setAncestors; setAncestors.insert(pool.mapTx.find(tx6.GetHash())); @@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) sortedOrder.erase(sortedOrder.begin()); sortedOrder.push_back(tx6.GetHash().ToString()); sortedOrder.push_back(tx7.GetHash().ToString()); - CheckSort<1>(pool, sortedOrder); + CheckSort<descendant_score>(pool, sortedOrder); /* low fee child of tx7 */ CMutableTransaction tx8 = CMutableTransaction(); @@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) // Now tx8 should be sorted low, but tx6/tx both high sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString()); - CheckSort<1>(pool, sortedOrder); + CheckSort<descendant_score>(pool, sortedOrder); /* low fee child of tx7 */ CMutableTransaction tx9 = CMutableTransaction(); @@ -232,7 +232,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) // tx9 should be sorted low BOOST_CHECK_EQUAL(pool.size(), 9); sortedOrder.insert(sortedOrder.begin(), tx9.GetHash().ToString()); - CheckSort<1>(pool, sortedOrder); + CheckSort<descendant_score>(pool, sortedOrder); std::vector<std::string> snapshotOrder = sortedOrder; @@ -274,18 +274,18 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) sortedOrder.insert(sortedOrder.begin()+5, tx9.GetHash().ToString()); sortedOrder.insert(sortedOrder.begin()+6, tx8.GetHash().ToString()); sortedOrder.insert(sortedOrder.begin()+7, tx10.GetHash().ToString()); // tx10 is just before tx6 - CheckSort<1>(pool, sortedOrder); + CheckSort<descendant_score>(pool, sortedOrder); // there should be 10 transactions in the mempool BOOST_CHECK_EQUAL(pool.size(), 10); // Now try removing tx10 and verify the sort order returns to normal std::list<CTransaction> removed; - pool.remove(pool.mapTx.find(tx10.GetHash())->GetTx(), removed, true); - CheckSort<1>(pool, snapshotOrder); + pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx(), removed); + CheckSort<descendant_score>(pool, snapshotOrder); - pool.remove(pool.mapTx.find(tx9.GetHash())->GetTx(), removed, true); - pool.remove(pool.mapTx.find(tx8.GetHash())->GetTx(), removed, true); + pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx(), removed); + pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx(), removed); /* Now check the sort on the mining score index. * Final order should be: * @@ -314,7 +314,111 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) sortedOrder.push_back(tx3.GetHash().ToString()); sortedOrder.push_back(tx6.GetHash().ToString()); } - CheckSort<3>(pool, sortedOrder); + CheckSort<mining_score>(pool, sortedOrder); +} + +BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) +{ + CTxMemPool pool(CFeeRate(0)); + TestMemPoolEntryHelper entry; + entry.hadNoDependencies = true; + + /* 3rd highest fee */ + CMutableTransaction tx1 = CMutableTransaction(); + tx1.vout.resize(1); + tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx1.vout[0].nValue = 10 * COIN; + pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1)); + + /* highest fee */ + CMutableTransaction tx2 = CMutableTransaction(); + tx2.vout.resize(1); + tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx2.vout[0].nValue = 2 * COIN; + pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2)); + uint64_t tx2Size = ::GetSerializeSize(tx2, SER_NETWORK, PROTOCOL_VERSION); + + /* lowest fee */ + CMutableTransaction tx3 = CMutableTransaction(); + tx3.vout.resize(1); + tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx3.vout[0].nValue = 5 * COIN; + pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3)); + + /* 2nd highest fee */ + CMutableTransaction tx4 = CMutableTransaction(); + tx4.vout.resize(1); + tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx4.vout[0].nValue = 6 * COIN; + pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4)); + + /* equal fee rate to tx1, but newer */ + CMutableTransaction tx5 = CMutableTransaction(); + tx5.vout.resize(1); + tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx5.vout[0].nValue = 11 * COIN; + pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); + BOOST_CHECK_EQUAL(pool.size(), 5); + + std::vector<std::string> sortedOrder; + sortedOrder.resize(5); + sortedOrder[0] = tx2.GetHash().ToString(); // 20000 + sortedOrder[1] = tx4.GetHash().ToString(); // 15000 + // tx1 and tx5 are both 10000 + // Ties are broken by hash, not timestamp, so determine which + // hash comes first. + if (tx1.GetHash() < tx5.GetHash()) { + sortedOrder[2] = tx1.GetHash().ToString(); + sortedOrder[3] = tx5.GetHash().ToString(); + } else { + sortedOrder[2] = tx5.GetHash().ToString(); + sortedOrder[3] = tx1.GetHash().ToString(); + } + sortedOrder[4] = tx3.GetHash().ToString(); // 0 + + CheckSort<ancestor_score>(pool, sortedOrder); + + /* low fee parent with high fee child */ + /* tx6 (0) -> tx7 (high) */ + CMutableTransaction tx6 = CMutableTransaction(); + tx6.vout.resize(1); + tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx6.vout[0].nValue = 20 * COIN; + uint64_t tx6Size = ::GetSerializeSize(tx6, SER_NETWORK, PROTOCOL_VERSION); + + pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6)); + BOOST_CHECK_EQUAL(pool.size(), 6); + sortedOrder.push_back(tx6.GetHash().ToString()); + CheckSort<ancestor_score>(pool, sortedOrder); + + CMutableTransaction tx7 = CMutableTransaction(); + tx7.vin.resize(1); + tx7.vin[0].prevout = COutPoint(tx6.GetHash(), 0); + tx7.vin[0].scriptSig = CScript() << OP_11; + tx7.vout.resize(1); + tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx7.vout[0].nValue = 10 * COIN; + uint64_t tx7Size = ::GetSerializeSize(tx7, SER_NETWORK, PROTOCOL_VERSION); + + /* set the fee to just below tx2's feerate when including ancestor */ + CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1; + + //CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true); + pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7)); + BOOST_CHECK_EQUAL(pool.size(), 7); + sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString()); + CheckSort<ancestor_score>(pool, sortedOrder); + + /* after tx6 is mined, tx7 should move up in the sort */ + std::vector<CTransaction> vtx; + vtx.push_back(tx6); + std::list<CTransaction> dummy; + pool.removeForBlock(vtx, 1, dummy, false); + + sortedOrder.erase(sortedOrder.begin()+1); + sortedOrder.pop_back(); + sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString()); + CheckSort<ancestor_score>(pool, sortedOrder); } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index f3297e074d..ab6485081c 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -247,13 +247,40 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // subsidy changing int nHeight = chainActive.Height(); - chainActive.Tip()->nHeight = 209999; + // Create an actual 209999-long block chain (without valid blocks). + while (chainActive.Tip()->nHeight < 209999) { + CBlockIndex* prev = chainActive.Tip(); + CBlockIndex* next = new CBlockIndex(); + next->phashBlock = new uint256(GetRandHash()); + pcoinsTip->SetBestBlock(next->GetBlockHash()); + next->pprev = prev; + next->nHeight = prev->nHeight + 1; + next->BuildSkip(); + chainActive.SetTip(next); + } BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; - chainActive.Tip()->nHeight = 210000; + // Extend to a 210000-long block chain. + while (chainActive.Tip()->nHeight < 210000) { + CBlockIndex* prev = chainActive.Tip(); + CBlockIndex* next = new CBlockIndex(); + next->phashBlock = new uint256(GetRandHash()); + pcoinsTip->SetBestBlock(next->GetBlockHash()); + next->pprev = prev; + next->nHeight = prev->nHeight + 1; + next->BuildSkip(); + chainActive.SetTip(next); + } BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; - chainActive.Tip()->nHeight = nHeight; + // Delete the dummy blocks again. + while (chainActive.Tip()->nHeight > nHeight) { + CBlockIndex* del = chainActive.Tip(); + chainActive.SetTip(del->pprev); + pcoinsTip->SetBestBlock(del->pprev->GetBlockHash()); + delete del->phashBlock; + delete del; + } // non-final txs in mempool SetMockTime(chainActive.Tip()->GetMedianTimePast()+1); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index f370a4aa2a..30e3f37e14 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -52,6 +52,64 @@ read_json(const std::string& jsondata) return v.get_array(); } +struct ScriptErrorDesc +{ + ScriptError_t err; + const char *name; +}; + +static ScriptErrorDesc script_errors[]={ + {SCRIPT_ERR_OK, "OK"}, + {SCRIPT_ERR_UNKNOWN_ERROR, "UNKNOWN_ERROR"}, + {SCRIPT_ERR_EVAL_FALSE, "EVAL_FALSE"}, + {SCRIPT_ERR_OP_RETURN, "OP_RETURN"}, + {SCRIPT_ERR_SCRIPT_SIZE, "SCRIPT_SIZE"}, + {SCRIPT_ERR_PUSH_SIZE, "PUSH_SIZE"}, + {SCRIPT_ERR_OP_COUNT, "OP_COUNT"}, + {SCRIPT_ERR_STACK_SIZE, "STACK_SIZE"}, + {SCRIPT_ERR_SIG_COUNT, "SIG_COUNT"}, + {SCRIPT_ERR_PUBKEY_COUNT, "PUBKEY_COUNT"}, + {SCRIPT_ERR_VERIFY, "VERIFY"}, + {SCRIPT_ERR_EQUALVERIFY, "EQUALVERIFY"}, + {SCRIPT_ERR_CHECKMULTISIGVERIFY, "CHECKMULTISIGVERIFY"}, + {SCRIPT_ERR_CHECKSIGVERIFY, "CHECKSIGVERIFY"}, + {SCRIPT_ERR_NUMEQUALVERIFY, "NUMEQUALVERIFY"}, + {SCRIPT_ERR_BAD_OPCODE, "BAD_OPCODE"}, + {SCRIPT_ERR_DISABLED_OPCODE, "DISABLED_OPCODE"}, + {SCRIPT_ERR_INVALID_STACK_OPERATION, "INVALID_STACK_OPERATION"}, + {SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, "INVALID_ALTSTACK_OPERATION"}, + {SCRIPT_ERR_UNBALANCED_CONDITIONAL, "UNBALANCED_CONDITIONAL"}, + {SCRIPT_ERR_NEGATIVE_LOCKTIME, "NEGATIVE_LOCKTIME"}, + {SCRIPT_ERR_UNSATISFIED_LOCKTIME, "UNSATISFIED_LOCKTIME"}, + {SCRIPT_ERR_SIG_HASHTYPE, "SIG_HASHTYPE"}, + {SCRIPT_ERR_SIG_DER, "SIG_DER"}, + {SCRIPT_ERR_MINIMALDATA, "MINIMALDATA"}, + {SCRIPT_ERR_SIG_PUSHONLY, "SIG_PUSHONLY"}, + {SCRIPT_ERR_SIG_HIGH_S, "SIG_HIGH_S"}, + {SCRIPT_ERR_SIG_NULLDUMMY, "SIG_NULLDUMMY"}, + {SCRIPT_ERR_PUBKEYTYPE, "PUBKEYTYPE"}, + {SCRIPT_ERR_CLEANSTACK, "CLEANSTACK"}, + {SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, "DISCOURAGE_UPGRADABLE_NOPS"} +}; + +const char *FormatScriptError(ScriptError_t err) +{ + for (unsigned int i=0; i<ARRAYLEN(script_errors); ++i) + if (script_errors[i].err == err) + return script_errors[i].name; + BOOST_ERROR("Unknown scripterror enumeration value, update script_errors in script_tests.cpp."); + return ""; +} + +ScriptError_t ParseScriptError(const std::string &name) +{ + for (unsigned int i=0; i<ARRAYLEN(script_errors); ++i) + if (script_errors[i].name == name) + return script_errors[i].err; + BOOST_ERROR("Unknown scripterror \"" << name << "\" in test description"); + return SCRIPT_ERR_UNKNOWN_ERROR; +} + BOOST_FIXTURE_TEST_SUITE(script_tests, BasicTestingSetup) CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey) @@ -87,13 +145,13 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMu return txSpend; } -void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message) +void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message, int scriptError) { ScriptError err; CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)); CMutableTransaction tx2 = tx; BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0), &err) == expect, message); - BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message); + BOOST_CHECK_MESSAGE(scriptError == -1 || err == scriptError, std::string(FormatScriptError(err)) + " where " + std::string(FormatScriptError((ScriptError_t)scriptError)) + " expected: " + message); #if defined(HAVE_CONSENSUS_LIB) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << tx2; @@ -187,6 +245,7 @@ private: std::vector<unsigned char> push; std::string comment; int flags; + int scriptError; void DoPush() { @@ -204,7 +263,7 @@ private: } public: - TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_) + TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_), scriptError(-1) { if (P2SH) { creditTx = BuildCreditingTransaction(CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL); @@ -214,6 +273,12 @@ public: spendTx = BuildSpendingTransaction(CScript(), creditTx); } + TestBuilder& ScriptError(ScriptError_t err) + { + scriptError = err; + return *this; + } + TestBuilder& Add(const CScript& script) { DoPush(); @@ -288,7 +353,7 @@ public: { TestBuilder copy = *this; // Make a copy so we can rollback the push. DoPush(); - DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, expect, comment); + DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, expect, comment, expect ? SCRIPT_ERR_OK : scriptError); *this = copy; return *this; } @@ -301,6 +366,8 @@ public: array.push_back(FormatScript(creditTx.vout[0].scriptPubKey)); array.push_back(FormatScriptFlags(flags)); array.push_back(comment); + if (scriptError != -1) + array.push_back(FormatScriptError((ScriptError_t)scriptError)); return array; } @@ -328,99 +395,99 @@ BOOST_AUTO_TEST_CASE(script_build) ).PushSig(keys.key0)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK, bad sig", 0 - ).PushSig(keys.key0).DamagePush(10)); + ).PushSig(keys.key0).DamagePush(10).ScriptError(SCRIPT_ERR_EVAL_FALSE)); good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH", 0 ).PushSig(keys.key1).Push(keys.pubkey1C)); bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey2C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH, bad pubkey", 0 - ).PushSig(keys.key2).Push(keys.pubkey2C).DamagePush(5)); + ).PushSig(keys.key2).Push(keys.pubkey2C).DamagePush(5).ScriptError(SCRIPT_ERR_EQUALVERIFY)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK anyonecanpay", 0 ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK anyonecanpay marked with normal hashtype", 0 - ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY).EditPush(70, "81", "01")); + ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY).EditPush(70, "81", "01").ScriptError(SCRIPT_ERR_EVAL_FALSE)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, "P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true ).PushSig(keys.key0).PushRedeem()); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, "P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true - ).PushSig(keys.key0).PushRedeem().DamagePush(10)); + ).PushSig(keys.key0).PushRedeem().DamagePush(10).ScriptError(SCRIPT_ERR_EVAL_FALSE)); good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true ).PushSig(keys.key0).DamagePush(10).PushRedeem()); bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH), bad sig", SCRIPT_VERIFY_P2SH, true - ).PushSig(keys.key0).DamagePush(10).PushRedeem()); + ).PushSig(keys.key0).DamagePush(10).PushRedeem().ScriptError(SCRIPT_ERR_EQUALVERIFY)); good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3", 0 ).Num(0).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); bad.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3, 2 sigs", 0 - ).Num(0).PushSig(keys.key0).PushSig(keys.key1).Num(0)); + ).Num(0).PushSig(keys.key0).PushSig(keys.key1).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE)); good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "P2SH(2-of-3)", SCRIPT_VERIFY_P2SH, true ).Num(0).PushSig(keys.key1).PushSig(keys.key2).PushRedeem()); bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "P2SH(2-of-3), 1 sig", SCRIPT_VERIFY_P2SH, true - ).Num(0).PushSig(keys.key1).Num(0).PushRedeem()); + ).Num(0).PushSig(keys.key1).Num(0).PushRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much R padding but no DERSIG", 0 ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much R padding", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); + ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").ScriptError(SCRIPT_ERR_SIG_DER)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much S padding but no DERSIG", 0 ).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100")); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much S padding", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100")); + ).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100").ScriptError(SCRIPT_ERR_SIG_DER)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too little R padding but no DERSIG", 0 ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too little R padding", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with bad sig with too much R padding but no DERSIG", 0 ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with bad sig with too much R padding", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10)); + ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10).ScriptError(SCRIPT_ERR_SIG_DER)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with too much R padding but no DERSIG", 0 - ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); + ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").ScriptError(SCRIPT_ERR_EVAL_FALSE)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with too much R padding", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); + ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").ScriptError(SCRIPT_ERR_SIG_DER)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 1, without DERSIG", 0 ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 1, with DERSIG", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 2, without DERSIG", 0 - ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_EVAL_FALSE)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 2, with DERSIG", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 3, without DERSIG", 0 - ).Num(0)); + ).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 3, with DERSIG", SCRIPT_VERIFY_DERSIG - ).Num(0)); + ).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, without DERSIG", 0 ).Num(0)); @@ -429,46 +496,46 @@ BOOST_AUTO_TEST_CASE(script_build) ).Num(0)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 5, without DERSIG", 0 - ).Num(1)); + ).Num(1).ScriptError(SCRIPT_ERR_EVAL_FALSE)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 5, with DERSIG", SCRIPT_VERIFY_DERSIG - ).Num(1)); + ).Num(1).ScriptError(SCRIPT_ERR_SIG_DER)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 6, without DERSIG", 0 ).Num(1)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 6, with DERSIG", SCRIPT_VERIFY_DERSIG - ).Num(1)); + ).Num(1).ScriptError(SCRIPT_ERR_SIG_DER)); good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 7, without DERSIG", 0 ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2)); bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 7, with DERSIG", SCRIPT_VERIFY_DERSIG - ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2)); + ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2).ScriptError(SCRIPT_ERR_SIG_DER)); bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 8, without DERSIG", 0 - ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2)); + ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2).ScriptError(SCRIPT_ERR_EVAL_FALSE)); bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 8, with DERSIG", SCRIPT_VERIFY_DERSIG - ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2)); + ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2).ScriptError(SCRIPT_ERR_SIG_DER)); bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 9, without DERSIG", 0 - ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_EVAL_FALSE)); bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 9, with DERSIG", SCRIPT_VERIFY_DERSIG - ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER)); good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 10, without DERSIG", 0 ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 10, with DERSIG", SCRIPT_VERIFY_DERSIG - ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER)); bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 11, without DERSIG", 0 - ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0)); + ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE)); bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 11, with DERSIG", SCRIPT_VERIFY_DERSIG - ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0)); + ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE)); good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 12, without DERSIG", 0 ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0)); @@ -480,33 +547,33 @@ BOOST_AUTO_TEST_CASE(script_build) ).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101")); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with multi-byte hashtype, with DERSIG", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101")); + ).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101").ScriptError(SCRIPT_ERR_SIG_DER)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with high S but no LOW_S", 0 ).PushSig(keys.key2, SIGHASH_ALL, 32, 33)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with high S", SCRIPT_VERIFY_LOW_S - ).PushSig(keys.key2, SIGHASH_ALL, 32, 33)); + ).PushSig(keys.key2, SIGHASH_ALL, 32, 33).ScriptError(SCRIPT_ERR_SIG_HIGH_S)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, "P2PK with hybrid pubkey but no STRICTENC", 0 ).PushSig(keys.key0, SIGHASH_ALL)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, "P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC - ).PushSig(keys.key0, SIGHASH_ALL)); + ).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with hybrid pubkey but no STRICTENC", 0 - ).PushSig(keys.key0, SIGHASH_ALL)); + ).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_EVAL_FALSE)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC - ).PushSig(keys.key0, SIGHASH_ALL)); + ).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0 ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC - ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10)); + ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10).ScriptError(SCRIPT_ERR_PUBKEYTYPE)); good.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the second 1 hybrid pubkey and no STRICTENC", 0 ).Num(0).PushSig(keys.key1, SIGHASH_ALL)); @@ -515,62 +582,61 @@ BOOST_AUTO_TEST_CASE(script_build) ).Num(0).PushSig(keys.key1, SIGHASH_ALL)); bad.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0H) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the first 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC - ).Num(0).PushSig(keys.key1, SIGHASH_ALL)); + ).Num(0).PushSig(keys.key1, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK with undefined hashtype but no STRICTENC", 0 ).PushSig(keys.key1, 5)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC - ).PushSig(keys.key1, 5)); + ).PushSig(keys.key1, 5).ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0 ).PushSig(keys.key1, 5).DamagePush(10)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC - ).PushSig(keys.key1, 5).DamagePush(10)); + ).PushSig(keys.key1, 5).DamagePush(10).ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3 with nonzero dummy but no NULLDUMMY", 0 ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); bad.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3 with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY - ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); + ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY", 0 ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10)); bad.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, "3-of-3 NOT with invalid sig with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY - ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10)); + ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10).ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY", 0 ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP)); bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs pushed using OP_DUP", SCRIPT_VERIFY_SIGPUSHONLY - ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP)); + ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP).ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", 0 - ).PushSig(keys.key2).PushRedeem()); + ).PushSig(keys.key2).PushRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig", SCRIPT_VERIFY_SIGPUSHONLY - ).PushSig(keys.key2).PushRedeem()); + ).PushSig(keys.key2).PushRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE)); good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY ).Num(0).PushSig(keys.key1).PushSig(keys.key1)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH ).Num(11).PushSig(keys.key0)); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH - ).Num(11).PushSig(keys.key0)); + ).Num(11).PushSig(keys.key0).ScriptError(SCRIPT_ERR_CLEANSTACK)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH, true ).Num(11).PushSig(keys.key0).PushRedeem()); bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true - ).Num(11).PushSig(keys.key0).PushRedeem()); + ).Num(11).PushSig(keys.key0).PushRedeem().ScriptError(SCRIPT_ERR_CLEANSTACK)); good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with CLEANSTACK", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true ).PushSig(keys.key0).PushRedeem()); @@ -585,11 +651,11 @@ BOOST_AUTO_TEST_CASE(script_build) for (unsigned int idx = 0; idx < json_good.size(); idx++) { const UniValue& tv = json_good[idx]; - tests_good.insert(tv.get_array().write()); + tests_good.insert(tv.get_array().write(1,4)); } for (unsigned int idx = 0; idx < json_bad.size(); idx++) { const UniValue& tv = json_bad[idx]; - tests_bad.insert(tv.get_array().write()); + tests_bad.insert(tv.get_array().write(1,4)); } } @@ -598,7 +664,7 @@ BOOST_AUTO_TEST_CASE(script_build) BOOST_FOREACH(TestBuilder& test, good) { test.Test(true); - std::string str = test.GetJSON().write(); + std::string str = test.GetJSON().write(1,4); #ifndef UPDATE_JSON_TESTS if (tests_good.count(str) == 0) { BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment()); @@ -608,7 +674,7 @@ BOOST_AUTO_TEST_CASE(script_build) } BOOST_FOREACH(TestBuilder& test, bad) { test.Test(false); - std::string str = test.GetJSON().write(); + std::string str = test.GetJSON().write(1,4); #ifndef UPDATE_JSON_TESTS if (tests_bad.count(str) == 0) { BOOST_CHECK_MESSAGE(false, "Missing auto script_invalid test: " + test.GetComment()); @@ -652,7 +718,7 @@ BOOST_AUTO_TEST_CASE(script_valid) CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); - DoTest(scriptPubKey, scriptSig, scriptflags, true, strTest); + DoTest(scriptPubKey, scriptSig, scriptflags, true, strTest, SCRIPT_ERR_OK); } } @@ -660,7 +726,6 @@ BOOST_AUTO_TEST_CASE(script_invalid) { // Scripts that should evaluate as invalid UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid))); - for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; string strTest = test.write(); @@ -676,8 +741,12 @@ BOOST_AUTO_TEST_CASE(script_invalid) string scriptPubKeyString = test[1].get_str(); CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); + int scriptError = -1; // Expected script error is optional, and follows comment + if (test.size() >= 5 && test[4].get_str() != "") { + scriptError = ParseScriptError(test[4].get_str()); + } - DoTest(scriptPubKey, scriptSig, scriptflags, false, strTest); + DoTest(scriptPubKey, scriptSig, scriptflags, false, strTest, scriptError); } } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 0416d0c926..dadc8b948f 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -17,12 +17,13 @@ #include "txdb.h" #include "txmempool.h" #include "ui_interface.h" -#include "util.h" #ifdef ENABLE_WALLET #include "wallet/db.h" #include "wallet/wallet.h" #endif +#include "test/testutil.h" + #include <boost/filesystem.hpp> #include <boost/test/unit_test.hpp> #include <boost/thread.hpp> @@ -151,7 +152,7 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPo CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0; return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight, - hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount); + hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount, lp); } void Shutdown(void* parg) diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index c623920880..769ae5a132 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -9,6 +9,7 @@ #include "key.h" #include "pubkey.h" #include "txdb.h" +#include "txmempool.h" #include <boost/filesystem.hpp> #include <boost/thread.hpp> @@ -71,7 +72,8 @@ struct TestMemPoolEntryHelper bool hadNoDependencies; bool spendsCoinbase; unsigned int sigOpCount; - + LockPoints lp; + TestMemPoolEntryHelper() : nFee(0), nTime(0), dPriority(0.0), nHeight(1), hadNoDependencies(false), spendsCoinbase(false), sigOpCount(1) { } diff --git a/src/test/testutil.cpp b/src/test/testutil.cpp new file mode 100644 index 0000000000..304cffb798 --- /dev/null +++ b/src/test/testutil.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2009-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. + +#include "testutil.h" + +#ifdef WIN32 +#include <shlobj.h> +#endif + +#include <boost/filesystem.hpp> + +boost::filesystem::path GetTempPath() { +#if BOOST_FILESYSTEM_VERSION == 3 + return boost::filesystem::temp_directory_path(); +#else + // TODO: remove when we don't support filesystem v2 anymore + boost::filesystem::path path; +#ifdef WIN32 + char pszPath[MAX_PATH] = ""; + + if (GetTempPathA(MAX_PATH, pszPath)) + path = boost::filesystem::path(pszPath); +#else + path = boost::filesystem::path("/tmp"); +#endif + if (path.empty() || !boost::filesystem::is_directory(path)) { + LogPrintf("GetTempPath(): failed to find temp path\n"); + return boost::filesystem::path(""); + } + return path; +#endif +} diff --git a/src/test/testutil.h b/src/test/testutil.h new file mode 100644 index 0000000000..5875dc50e6 --- /dev/null +++ b/src/test/testutil.h @@ -0,0 +1,15 @@ +// Copyright (c) 2009-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. + +/** + * Utility functions shared by unit tests + */ +#ifndef BITCOIN_TEST_TESTUTIL_H +#define BITCOIN_TEST_TESTUTIL_H + +#include <boost/filesystem/path.hpp> + +boost::filesystem::path GetTempPath(); + +#endif // BITCOIN_TEST_TESTUTIL_H diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index c29e30792a..237b26329b 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -23,7 +23,7 @@ ToMemPool(CMutableTransaction& tx) LOCK(cs_main); CValidationState state; - return AcceptToMemoryPool(mempool, state, tx, false, NULL, true, 0); + return AcceptToMemoryPool(mempool, state, tx, false, NULL, NULL, true, 0); } BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 43e8ae9b36..b99f952a0d 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -200,6 +200,8 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney) BOOST_CHECK_EQUAL(ret, COIN*10); BOOST_CHECK(ParseMoney("1.00", ret)); BOOST_CHECK_EQUAL(ret, COIN); + BOOST_CHECK(ParseMoney("1", ret)); + BOOST_CHECK_EQUAL(ret, COIN); BOOST_CHECK(ParseMoney("0.1", ret)); BOOST_CHECK_EQUAL(ret, COIN/10); BOOST_CHECK(ParseMoney("0.01", ret)); @@ -219,6 +221,9 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney) // Attempted 63 bit overflow should fail BOOST_CHECK(!ParseMoney("92233720368.54775808", ret)); + + // Parsing negative amounts must fail + BOOST_CHECK(!ParseMoney("-1", ret)); } BOOST_AUTO_TEST_CASE(util_IsHex) diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp new file mode 100644 index 0000000000..1f86a06a3f --- /dev/null +++ b/src/test/versionbits_tests.cpp @@ -0,0 +1,316 @@ +// Copyright (c) 2014-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chain.h" +#include "random.h" +#include "versionbits.h" +#include "test/test_bitcoin.h" +#include "chainparams.h" +#include "main.h" +#include "consensus/params.h" + +#include <boost/test/unit_test.hpp> + +/* Define a virtual block time, one block per 10 minutes after Nov 14 2014, 0:55:36am */ +int32_t TestTime(int nHeight) { return 1415926536 + 600 * nHeight; } + +static const Consensus::Params paramsDummy = Consensus::Params(); + +class TestConditionChecker : public AbstractThresholdConditionChecker +{ +private: + mutable ThresholdConditionCache cache; + +public: + int64_t BeginTime(const Consensus::Params& params) const { return TestTime(10000); } + int64_t EndTime(const Consensus::Params& params) const { return TestTime(20000); } + int Period(const Consensus::Params& params) const { return 1000; } + int Threshold(const Consensus::Params& params) const { return 900; } + bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const { return (pindex->nVersion & 0x100); } + + ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, paramsDummy, cache); } +}; + +#define CHECKERS 6 + +class VersionBitsTester +{ + // A fake blockchain + std::vector<CBlockIndex*> vpblock; + + // 6 independent checkers for the same bit. + // The first one performs all checks, the second only 50%, the third only 25%, etc... + // This is to test whether lack of cached information leads to the same results. + TestConditionChecker checker[CHECKERS]; + + // Test counter (to identify failures) + int num; + +public: + VersionBitsTester() : num(0) {} + + VersionBitsTester& Reset() { + for (unsigned int i = 0; i < vpblock.size(); i++) { + delete vpblock[i]; + } + for (unsigned int i = 0; i < CHECKERS; i++) { + checker[i] = TestConditionChecker(); + } + vpblock.clear(); + return *this; + } + + ~VersionBitsTester() { + Reset(); + } + + VersionBitsTester& Mine(unsigned int height, int32_t nTime, int32_t nVersion) { + while (vpblock.size() < height) { + CBlockIndex* pindex = new CBlockIndex(); + pindex->nHeight = vpblock.size(); + pindex->pprev = vpblock.size() > 0 ? vpblock.back() : NULL; + pindex->nTime = nTime; + pindex->nVersion = nVersion; + pindex->BuildSkip(); + vpblock.push_back(pindex); + } + return *this; + } + + VersionBitsTester& TestDefined() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_DEFINED, strprintf("Test %i for DEFINED", num)); + } + } + num++; + return *this; + } + + VersionBitsTester& TestStarted() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_STARTED, strprintf("Test %i for STARTED", num)); + } + } + num++; + return *this; + } + + VersionBitsTester& TestLockedIn() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_LOCKED_IN, strprintf("Test %i for LOCKED_IN", num)); + } + } + num++; + return *this; + } + + VersionBitsTester& TestActive() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE", num)); + } + } + num++; + return *this; + } + + VersionBitsTester& TestFailed() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_FAILED, strprintf("Test %i for FAILED", num)); + } + } + num++; + return *this; + } + + CBlockIndex * Tip() { return vpblock.size() ? vpblock.back() : NULL; } +}; + +BOOST_FIXTURE_TEST_SUITE(versionbits_tests, TestingSetup) + +BOOST_AUTO_TEST_CASE(versionbits_test) +{ + for (int i = 0; i < 64; i++) { + // DEFINED -> FAILED + VersionBitsTester().TestDefined() + .Mine(1, TestTime(1), 0x100).TestDefined() + .Mine(11, TestTime(11), 0x100).TestDefined() + .Mine(989, TestTime(989), 0x100).TestDefined() + .Mine(999, TestTime(20000), 0x100).TestDefined() + .Mine(1000, TestTime(20000), 0x100).TestFailed() + .Mine(1999, TestTime(30001), 0x100).TestFailed() + .Mine(2000, TestTime(30002), 0x100).TestFailed() + .Mine(2001, TestTime(30003), 0x100).TestFailed() + .Mine(2999, TestTime(30004), 0x100).TestFailed() + .Mine(3000, TestTime(30005), 0x100).TestFailed() + + // DEFINED -> STARTED -> FAILED + .Reset().TestDefined() + .Mine(1, TestTime(1), 0).TestDefined() + .Mine(1000, TestTime(10000) - 1, 0x100).TestDefined() // One second more and it would be defined + .Mine(2000, TestTime(10000), 0x100).TestStarted() // So that's what happens the next period + .Mine(2051, TestTime(10010), 0).TestStarted() // 51 old blocks + .Mine(2950, TestTime(10020), 0x100).TestStarted() // 899 new blocks + .Mine(3000, TestTime(20000), 0).TestFailed() // 50 old blocks (so 899 out of the past 1000) + .Mine(4000, TestTime(20010), 0x100).TestFailed() + + // DEFINED -> STARTED -> FAILED while threshold reached + .Reset().TestDefined() + .Mine(1, TestTime(1), 0).TestDefined() + .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined + .Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period + .Mine(2999, TestTime(30000), 0x100).TestStarted() // 999 new blocks + .Mine(3000, TestTime(30000), 0x100).TestFailed() // 1 new block (so 1000 out of the past 1000 are new) + .Mine(3999, TestTime(30001), 0).TestFailed() + .Mine(4000, TestTime(30002), 0).TestFailed() + .Mine(14333, TestTime(30003), 0).TestFailed() + .Mine(24000, TestTime(40000), 0).TestFailed() + + // DEFINED -> STARTED -> LOCKEDIN at the last minute -> ACTIVE + .Reset().TestDefined() + .Mine(1, TestTime(1), 0).TestDefined() + .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined + .Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period + .Mine(2050, TestTime(10010), 0x200).TestStarted() // 50 old blocks + .Mine(2950, TestTime(10020), 0x100).TestStarted() // 900 new blocks + .Mine(2999, TestTime(19999), 0x200).TestStarted() // 49 old blocks + .Mine(3000, TestTime(29999), 0x200).TestLockedIn() // 1 old block (so 900 out of the past 1000) + .Mine(3999, TestTime(30001), 0).TestLockedIn() + .Mine(4000, TestTime(30002), 0).TestActive() + .Mine(14333, TestTime(30003), 0).TestActive() + .Mine(24000, TestTime(40000), 0).TestActive(); + } + + // Sanity checks of version bit deployments + const Consensus::Params &mainnetParams = Params(CBaseChainParams::MAIN).GetConsensus(); + for (int i=0; i<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { + uint32_t bitmask = VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)i); + // Make sure that no deployment tries to set an invalid bit. + BOOST_CHECK_EQUAL(bitmask & ~(uint32_t)VERSIONBITS_TOP_MASK, bitmask); + + // Verify that the deployment windows of different deployment using the + // same bit are disjoint. + // This test may need modification at such time as a new deployment + // is proposed that reuses the bit of an activated soft fork, before the + // end time of that soft fork. (Alternatively, the end time of that + // activated soft fork could be later changed to be earlier to avoid + // overlap.) + for (int j=i+1; j<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; j++) { + if (VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)j) == bitmask) { + BOOST_CHECK(mainnetParams.vDeployments[j].nStartTime > mainnetParams.vDeployments[i].nTimeout || + mainnetParams.vDeployments[i].nStartTime > mainnetParams.vDeployments[j].nTimeout); + } + } + } +} + +BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) +{ + // Check that ComputeBlockVersion will set the appropriate bit correctly + // on mainnet. + const Consensus::Params &mainnetParams = Params(CBaseChainParams::MAIN).GetConsensus(); + + // Use the TESTDUMMY deployment for testing purposes. + int64_t bit = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit; + int64_t nStartTime = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime; + int64_t nTimeout = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout; + + assert(nStartTime < nTimeout); + + // In the first chain, test that the bit is set by CBV until it has failed. + // In the second chain, test the bit is set by CBV while STARTED and + // LOCKED-IN, and then no longer set while ACTIVE. + VersionBitsTester firstChain, secondChain; + + // Start generating blocks before nStartTime + int64_t nTime = nStartTime - 1; + + // Before MedianTimePast of the chain has crossed nStartTime, the bit + // should not be set. + CBlockIndex *lastBlock = NULL; + lastBlock = firstChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); + + // Mine 2011 more blocks at the old time, and check that CBV isn't setting the bit yet. + for (int i=1; i<2012; i++) { + lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + // This works because VERSIONBITS_LAST_OLD_BLOCK_VERSION happens + // to be 4, and the bit we're testing happens to be bit 28. + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); + } + // Now mine 5 more blocks at the start time -- MTP should not have passed yet, so + // CBV should still not yet set the bit. + nTime = nStartTime; + for (int i=2012; i<=2016; i++) { + lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); + } + + // Advance to the next period and transition to STARTED, + lastBlock = firstChain.Mine(6048, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + // so ComputeBlockVersion should now set the bit, + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + // and should also be using the VERSIONBITS_TOP_BITS. + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); + + // Check that ComputeBlockVersion will set the bit until nTimeout + nTime += 600; + int blocksToMine = 4032; // test blocks for up to 2 time periods + int nHeight = 6048; + // These blocks are all before nTimeout is reached. + while (nTime < nTimeout && blocksToMine > 0) { + lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); + blocksToMine--; + nTime += 600; + nHeight += 1; + }; + + nTime = nTimeout; + // FAILED is only triggered at the end of a period, so CBV should be setting + // the bit until the period transition. + for (int i=0; i<2015; i++) { + lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + nHeight += 1; + } + // The next block should trigger no longer setting the bit. + lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); + + // On a new chain: + // verify that the bit will be set after lock-in, and then stop being set + // after activation. + nTime = nStartTime; + + // Mine one period worth of blocks, and check that the bit will be on for the + // next period. + lastBlock = secondChain.Mine(2016, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + + // Mine another period worth of blocks, signaling the new bit. + lastBlock = secondChain.Mine(4032, nStartTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip(); + // After one period of setting the bit on each block, it should have locked in. + // We keep setting the bit for one more period though, until activation. + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + + // Now check that we keep mining the block until the end of this period, and + // then stop at the beginning of the next period. + lastBlock = secondChain.Mine(6047, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + lastBlock = secondChain.Mine(6048, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); + + // Finally, verify that after a soft fork has activated, CBV no longer uses + // VERSIONBITS_LAST_OLD_BLOCK_VERSION. + //BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 10170dbcea..1c7bc2dbee 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -393,11 +393,14 @@ private: static void reconnect_cb(evutil_socket_t fd, short what, void *arg); }; -TorController::TorController(struct event_base* base, const std::string& target): - base(base), +TorController::TorController(struct event_base* baseIn, const std::string& target): + base(baseIn), target(target), conn(base), reconnect(true), reconnect_ev(0), reconnect_timeout(RECONNECT_TIMEOUT_START) { + reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); + if (!reconnect_ev) + LogPrintf("tor: Failed to create event for reconnection: out of memory?\n"); // Start connection attempts immediately if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1), boost::bind(&TorController::disconnected_cb, this, _1) )) { @@ -413,8 +416,10 @@ TorController::TorController(struct event_base* base, const std::string& target) TorController::~TorController() { - if (reconnect_ev) - event_del(reconnect_ev); + if (reconnect_ev) { + event_free(reconnect_ev); + reconnect_ev = 0; + } if (service.IsValid()) { RemoveLocal(service); } @@ -459,7 +464,7 @@ void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& r if (GetArg("-onion", "") == "") { proxyType addrOnion = proxyType(CService("127.0.0.1", 9050), true); SetProxy(NET_TOR, addrOnion); - SetReachable(NET_TOR); + SetLimited(NET_TOR, false); } // Finally - now create the service @@ -626,8 +631,8 @@ void TorController::disconnected_cb(TorControlConnection& conn) // Single-shot timer for reconnect. Use exponential backoff. struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0)); - reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); - event_add(reconnect_ev, &time); + if (reconnect_ev) + event_add(reconnect_ev, &time); reconnect_timeout *= RECONNECT_TIMEOUT_EXP; } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 0b0f32e406..52c7793118 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -22,10 +22,10 @@ using namespace std; 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): + bool _spendsCoinbase, unsigned int _sigOps, LockPoints lp): tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), - spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps) + spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp) { nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); nModSize = tx.CalculateModifiedSize(nTxSize); @@ -38,6 +38,11 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, assert(inChainInputValue <= nValueIn); feeDelta = 0; + + nCountWithAncestors = 1; + nSizeWithAncestors = nTxSize; + nModFeesWithAncestors = nFee; + nSigOpCountWithAncestors = sigOpCount; } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) @@ -58,27 +63,25 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta) { nModFeesWithDescendants += newFeeDelta - feeDelta; + nModFeesWithAncestors += newFeeDelta - feeDelta; feeDelta = newFeeDelta; } +void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp) +{ + lockPoints = lp; +} + // Update the given tx for any in-mempool descendants. // Assumes that setMemPoolChildren is correct for the given tx and all // descendants. -bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit, cacheMap &cachedDescendants, const std::set<uint256> &setExclude) +void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set<uint256> &setExclude) { - // Track the number of entries (outside setExclude) that we'd need to visit - // (will bail out if it exceeds maxDescendantsToVisit) - int nChildrenToVisit = 0; - setEntries stageEntries, setAllDescendants; stageEntries = GetMemPoolChildren(updateIt); while (!stageEntries.empty()) { const txiter cit = *stageEntries.begin(); - if (cit->IsDirty()) { - // Don't consider any more children if any descendant is dirty - return false; - } setAllDescendants.insert(cit); stageEntries.erase(cit); const setEntries &setChildren = GetMemPoolChildren(cit); @@ -88,22 +91,11 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit // We've already calculated this one, just add the entries for this set // but don't traverse again. BOOST_FOREACH(const txiter cacheEntry, cacheIt->second) { - // update visit count only for new child transactions - // (outside of setExclude and stageEntries) - if (setAllDescendants.insert(cacheEntry).second && - !setExclude.count(cacheEntry->GetTx().GetHash()) && - !stageEntries.count(cacheEntry)) { - nChildrenToVisit++; - } + setAllDescendants.insert(cacheEntry); } } else if (!setAllDescendants.count(childEntry)) { - // Schedule for later processing and update our visit count - if (stageEntries.insert(childEntry).second && !setExclude.count(childEntry->GetTx().GetHash())) { - nChildrenToVisit++; - } - } - if (nChildrenToVisit > maxDescendantsToVisit) { - return false; + // Schedule for later processing + stageEntries.insert(childEntry); } } } @@ -118,16 +110,18 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit modifyFee += cit->GetModifiedFee(); modifyCount++; cachedDescendants[updateIt].insert(cit); + // Update ancestor state for each descendant + mapTx.modify(cit, update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCount())); } } mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount)); - return true; } // vHashesToUpdate is the set of transaction hashes from a disconnected block // which has been re-added to the mempool. // for each entry, look for descendants that are outside hashesToUpdate, and // add fee/size information for such descendants to the parent. +// for each such descendant, also update the ancestor state to include the parent. void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate) { LOCK(cs); @@ -167,14 +161,11 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes UpdateParent(childIter, it, true); } } - if (!UpdateForDescendants(it, 100, mapMemPoolDescendantsToUpdate, setAlreadyIncluded)) { - // Mark as dirty if we can't do the calculation. - mapTx.modify(it, set_dirty()); - } + UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded); } } -bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) +bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) const { setEntries parentHashes; const CTransaction &tx = entry.GetTx(); @@ -251,6 +242,20 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors } } +void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncestors) +{ + int64_t updateCount = setAncestors.size(); + int64_t updateSize = 0; + CAmount updateFee = 0; + int updateSigOps = 0; + BOOST_FOREACH(txiter ancestorIt, setAncestors) { + updateSize += ancestorIt->GetTxSize(); + updateFee += ancestorIt->GetModifiedFee(); + updateSigOps += ancestorIt->GetSigOpCount(); + } + mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, updateSigOps)); +} + void CTxMemPool::UpdateChildrenForRemoval(txiter it) { const setEntries &setMemPoolChildren = GetMemPoolChildren(it); @@ -259,11 +264,30 @@ void CTxMemPool::UpdateChildrenForRemoval(txiter it) } } -void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) +void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants) { // For each entry, walk back all ancestors and decrement size associated with this // transaction const uint64_t nNoLimit = std::numeric_limits<uint64_t>::max(); + if (updateDescendants) { + // updateDescendants should be true whenever we're not recursively + // removing a tx and all its descendants, eg when a transaction is + // confirmed in a block. + // Here we only update statistics and not data in mapLinks (which + // we need to preserve until we're finished with all operations that + // need to traverse the mempool). + BOOST_FOREACH(txiter removeIt, entriesToRemove) { + setEntries setDescendants; + CalculateDescendants(removeIt, setDescendants); + setDescendants.erase(removeIt); // don't update state for self + int64_t modifySize = -((int64_t)removeIt->GetTxSize()); + CAmount modifyFee = -removeIt->GetModifiedFee(); + int modifySigOps = -removeIt->GetSigOpCount(); + BOOST_FOREACH(txiter dit, setDescendants) { + mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, -1, modifySigOps)); + } + } + } BOOST_FOREACH(txiter removeIt, entriesToRemove) { setEntries setAncestors; const CTxMemPoolEntry &entry = *removeIt; @@ -287,10 +311,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) // transactions as the set of things to update for removal. CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); // Note that UpdateAncestorsOf severs the child links that point to - // removeIt in the entries for the parents of removeIt. This is - // fine since we don't need to use the mempool children of any entries - // to walk back over our ancestors (but we do need the mempool - // parents!) + // removeIt in the entries for the parents of removeIt. UpdateAncestorsOf(false, removeIt, setAncestors); } // After updating all the ancestor sizes, we can now sever the link between each @@ -301,22 +322,24 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) } } -void CTxMemPoolEntry::SetDirty() +void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) { - nCountWithDescendants = 0; - nSizeWithDescendants = nTxSize; - nModFeesWithDescendants = GetModifiedFee(); + nSizeWithDescendants += modifySize; + assert(int64_t(nSizeWithDescendants) > 0); + nModFeesWithDescendants += modifyFee; + nCountWithDescendants += modifyCount; + assert(int64_t(nCountWithDescendants) > 0); } -void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) +void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps) { - if (!IsDirty()) { - nSizeWithDescendants += modifySize; - assert(int64_t(nSizeWithDescendants) > 0); - nModFeesWithDescendants += modifyFee; - nCountWithDescendants += modifyCount; - assert(int64_t(nCountWithDescendants) > 0); - } + nSizeWithAncestors += modifySize; + assert(int64_t(nSizeWithAncestors) > 0); + nModFeesWithAncestors += modifyFee; + nCountWithAncestors += modifyCount; + assert(int64_t(nCountWithAncestors) > 0); + nSigOpCountWithAncestors += modifySigOps; + assert(int(nSigOpCountWithAncestors) >= 0); } CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) : @@ -409,6 +432,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, } } UpdateAncestorsOf(true, newit, setAncestors); + UpdateEntryForAncestors(newit, setAncestors); nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); @@ -461,7 +485,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants } } -void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& removed, bool fRecursive) +void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list<CTransaction>& removed) { // Remove transaction from memory pool { @@ -470,8 +494,8 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem txiter origit = mapTx.find(origTx.GetHash()); if (origit != mapTx.end()) { txToRemove.insert(origit); - } else if (fRecursive) { - // If recursively removing but origTx isn't in the mempool + } else { + // When recursively removing but origTx isn't in the mempool // be sure to remove any children that are in the pool. This can // happen during chain re-orgs if origTx isn't re-accepted into // the mempool for any reason. @@ -485,17 +509,13 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem } } setEntries setAllRemoves; - if (fRecursive) { - BOOST_FOREACH(txiter it, txToRemove) { - CalculateDescendants(it, setAllRemoves); - } - } else { - setAllRemoves.swap(txToRemove); + BOOST_FOREACH(txiter it, txToRemove) { + CalculateDescendants(it, setAllRemoves); } BOOST_FOREACH(txiter it, setAllRemoves) { removed.push_back(it->GetTx()); } - RemoveStaged(setAllRemoves); + RemoveStaged(setAllRemoves, false); } } @@ -506,7 +526,11 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem list<CTransaction> transactionsToRemove; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->GetTx(); - if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(tx, flags)) { + LockPoints lp = it->GetLockPoints(); + bool validLP = TestLockPointValidity(&lp); + if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(tx, flags, &lp, validLP)) { + // Note if CheckSequenceLocks fails the LockPoints may still be invalid + // So it's critical that we remove the tx and not depend on the LockPoints. transactionsToRemove.push_back(tx); } else if (it->GetSpendsCoinbase()) { BOOST_FOREACH(const CTxIn& txin, tx.vin) { @@ -521,10 +545,13 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem } } } + if (!validLP) { + mapTx.modify(it, update_lock_points(lp)); + } } BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) { list<CTransaction> removed; - remove(tx, removed, true); + removeRecursive(tx, removed); } } @@ -539,7 +566,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction> const CTransaction &txConflict = *it->second.ptx; if (txConflict != tx) { - remove(txConflict, removed, true); + removeRecursive(txConflict, removed); ClearPrioritisation(txConflict.GetHash()); } } @@ -564,8 +591,12 @@ void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned i } BOOST_FOREACH(const CTransaction& tx, vtx) { - std::list<CTransaction> dummy; - remove(tx, dummy, false); + txiter it = mapTx.find(tx.GetHash()); + if (it != mapTx.end()) { + setEntries stage; + stage.insert(it); + RemoveStaged(stage, true); + } removeConflicts(tx, conflicts); ClearPrioritisation(tx.GetHash()); } @@ -622,6 +653,8 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children); bool fDependsWait = false; setEntries setParentCheck; + int64_t parentSizes = 0; + unsigned int parentSigOpCount = 0; BOOST_FOREACH(const CTxIn &txin, tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); @@ -629,7 +662,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const const CTransaction& tx2 = it2->GetTx(); assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); fDependsWait = true; - setParentCheck.insert(it2); + if (setParentCheck.insert(it2).second) { + parentSizes += it2->GetTxSize(); + parentSigOpCount += it2->GetSigOpCount(); + } } else { const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash); assert(coins && coins->IsAvailable(txin.prevout.n)); @@ -642,28 +678,42 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const i++; } assert(setParentCheck == GetMemPoolParents(it)); + // Verify ancestor state is correct. + setEntries setAncestors; + uint64_t nNoLimit = std::numeric_limits<uint64_t>::max(); + std::string dummy; + CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); + uint64_t nCountCheck = setAncestors.size() + 1; + uint64_t nSizeCheck = it->GetTxSize(); + CAmount nFeesCheck = it->GetModifiedFee(); + unsigned int nSigOpCheck = it->GetSigOpCount(); + + BOOST_FOREACH(txiter ancestorIt, setAncestors) { + nSizeCheck += ancestorIt->GetTxSize(); + nFeesCheck += ancestorIt->GetModifiedFee(); + nSigOpCheck += ancestorIt->GetSigOpCount(); + } + + assert(it->GetCountWithAncestors() == nCountCheck); + assert(it->GetSizeWithAncestors() == nSizeCheck); + assert(it->GetSigOpCountWithAncestors() == nSigOpCheck); + assert(it->GetModFeesWithAncestors() == nFeesCheck); + // Check children against mapNextTx CTxMemPool::setEntries setChildrenCheck; std::map<COutPoint, CInPoint>::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); int64_t childSizes = 0; - CAmount childModFee = 0; for (; iter != mapNextTx.end() && iter->first.hash == it->GetTx().GetHash(); ++iter) { txiter childit = mapTx.find(iter->second.ptx->GetHash()); assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions if (setChildrenCheck.insert(childit).second) { childSizes += childit->GetTxSize(); - childModFee += childit->GetModifiedFee(); } } assert(setChildrenCheck == GetMemPoolChildren(it)); // Also check to make sure size is greater than sum with immediate children. // just a sanity check, not definitive that this calc is correct... - if (!it->IsDirty()) { - assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize()); - } else { - assert(it->GetSizeWithDescendants() == it->GetTxSize()); - assert(it->GetModFeesWithDescendants() == it->GetModifiedFee()); - } + assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize()); if (fDependsWait) waitingOnDependants.push_back(&(*it)); @@ -721,6 +771,16 @@ bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const return true; } +bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) 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; +} + CFeeRate CTxMemPool::estimateFee(int nBlocks) const { LOCK(cs); @@ -845,13 +905,13 @@ bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { size_t CTxMemPool::DynamicMemoryUsage() const { LOCK(cs); - // Estimate the overhead of mapTx to be 12 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. - return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 12 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage; + // Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. + return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage; } -void CTxMemPool::RemoveStaged(setEntries &stage) { +void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants) { AssertLockHeld(cs); - UpdateForRemoveFromMempool(stage); + UpdateForRemoveFromMempool(stage, updateDescendants); BOOST_FOREACH(const txiter& it, stage) { removeUnchecked(it); } @@ -859,9 +919,9 @@ void CTxMemPool::RemoveStaged(setEntries &stage) { int CTxMemPool::Expire(int64_t time) { LOCK(cs); - indexed_transaction_set::nth_index<2>::type::iterator it = mapTx.get<2>().begin(); + indexed_transaction_set::index<entry_time>::type::iterator it = mapTx.get<entry_time>().begin(); setEntries toremove; - while (it != mapTx.get<2>().end() && it->GetTime() < time) { + while (it != mapTx.get<entry_time>().end() && it->GetTime() < time) { toremove.insert(mapTx.project<0>(it)); it++; } @@ -869,7 +929,7 @@ int CTxMemPool::Expire(int64_t time) { BOOST_FOREACH(txiter removeit, toremove) { CalculateDescendants(removeit, stage); } - RemoveStaged(stage); + RemoveStaged(stage, false); return stage.size(); } @@ -957,7 +1017,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe unsigned nTxnRemoved = 0; CFeeRate maxFeeRateRemoved(0); while (DynamicMemoryUsage() > sizelimit) { - indexed_transaction_set::nth_index<1>::type::iterator it = mapTx.get<1>().begin(); + indexed_transaction_set::index<descendant_score>::type::iterator it = mapTx.get<descendant_score>().begin(); // We set the new mempool min fee to the feerate of the removed set, plus the // "minimum reasonable fee rate" (ie some value under which we consider txn @@ -978,7 +1038,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe BOOST_FOREACH(txiter it, stage) txn.push_back(it->GetTx()); } - RemoveStaged(stage); + RemoveStaged(stage, false); if (pvNoSpendsRemaining) { BOOST_FOREACH(const CTransaction& tx, txn) { BOOST_FOREACH(const CTxIn& txin, tx.vin) { diff --git a/src/txmempool.h b/src/txmempool.h index 386cb26d25..9dbb37dad0 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -19,6 +19,7 @@ #include "boost/multi_index/ordered_index.hpp" class CAutoFile; +class CBlockIndex; inline double AllowFreeThreshold() { @@ -35,6 +36,21 @@ inline bool AllowFree(double dPriority) /** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */ static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF; +struct LockPoints +{ + // Will be set to the blockchain height and median time past + // values that would be necessary to satisfy all relative locktime + // constraints (BIP68) of this tx given our view of block chain history + int height; + int64_t time; + // As long as the current chain descends from the highest height block + // containing one of the inputs used in the calculation, then the cached + // values are still valid even after a reorg. + CBlockIndex* maxInputBlock; + + LockPoints() : height(0), time(0), maxInputBlock(NULL) { } +}; + class CTxMemPool; /** \class CTxMemPoolEntry @@ -70,6 +86,7 @@ private: bool spendsCoinbase; //! keep track of transactions that spend a coinbase unsigned int sigOpCount; //! Legacy sig ops plus P2SH sig op count int64_t feeDelta; //! Used for determining the priority of the transaction for mining in a block + LockPoints lockPoints; //! Track the height and time at which tx was final // Information about descendants of this transaction that are in the // mempool; if we remove this transaction we must remove all of these @@ -80,11 +97,17 @@ private: uint64_t nSizeWithDescendants; //! ... and size CAmount nModFeesWithDescendants; //! ... and total fees (all including us) + // Analogous statistics for ancestor transactions + uint64_t nCountWithAncestors; + uint64_t nSizeWithAncestors; + CAmount nModFeesWithAncestors; + unsigned int nSigOpCountWithAncestors; + public: CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, bool poolHasNoInputsOf, CAmount _inChainInputValue, bool spendsCoinbase, - unsigned int nSigOps); + unsigned int nSigOps, LockPoints lp); CTxMemPoolEntry(const CTxMemPoolEntry& other); const CTransaction& GetTx() const { return this->tx; } @@ -101,25 +124,28 @@ public: unsigned int GetSigOpCount() const { return sigOpCount; } int64_t GetModifiedFee() const { return nFee + feeDelta; } size_t DynamicMemoryUsage() const { return nUsageSize; } + const LockPoints& GetLockPoints() const { return lockPoints; } // Adjusts the descendant state, if this entry is not dirty. - void UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount); + void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount); + // Adjusts the ancestor state + void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps); // Updates the fee delta used for mining priority score, and the // modified fees with descendants. void UpdateFeeDelta(int64_t feeDelta); - - /** We can set the entry to be dirty if doing the full calculation of in- - * mempool descendants will be too expensive, which can potentially happen - * when re-adding transactions from a block back to the mempool. - */ - void SetDirty(); - bool IsDirty() const { return nCountWithDescendants == 0; } + // Update the LockPoints after a reorg + void UpdateLockPoints(const LockPoints& lp); uint64_t GetCountWithDescendants() const { return nCountWithDescendants; } uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; } CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; } bool GetSpendsCoinbase() const { return spendsCoinbase; } + + uint64_t GetCountWithAncestors() const { return nCountWithAncestors; } + uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; } + CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; } + unsigned int GetSigOpCountWithAncestors() const { return nSigOpCountWithAncestors; } }; // Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index. @@ -130,7 +156,7 @@ struct update_descendant_state {} void operator() (CTxMemPoolEntry &e) - { e.UpdateState(modifySize, modifyFee, modifyCount); } + { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); } private: int64_t modifySize; @@ -138,10 +164,20 @@ struct update_descendant_state int64_t modifyCount; }; -struct set_dirty +struct update_ancestor_state { + update_ancestor_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount, int _modifySigOps) : + modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount), modifySigOps(_modifySigOps) + {} + void operator() (CTxMemPoolEntry &e) - { e.SetDirty(); } + { e.UpdateAncestorState(modifySize, modifyFee, modifyCount, modifySigOps); } + + private: + int64_t modifySize; + CAmount modifyFee; + int64_t modifyCount; + int modifySigOps; }; struct update_fee_delta @@ -154,6 +190,16 @@ private: int64_t feeDelta; }; +struct update_lock_points +{ + update_lock_points(const LockPoints& _lp) : lp(_lp) { } + + void operator() (CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); } + +private: + const LockPoints& lp; +}; + // extracts a TxMemPoolEntry's transaction hash struct mempoolentry_txid { @@ -228,6 +274,35 @@ public: } }; +class CompareTxMemPoolEntryByAncestorFee +{ +public: + bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) + { + double aFees = a.GetModFeesWithAncestors(); + double aSize = a.GetSizeWithAncestors(); + + double bFees = b.GetModFeesWithAncestors(); + double bSize = b.GetSizeWithAncestors(); + + // Avoid division by rewriting (a/b > c/d) as (a*d > c*b). + double f1 = aFees * bSize; + double f2 = aSize * bFees; + + if (f1 == f2) { + return a.GetTx().GetHash() < b.GetTx().GetHash(); + } + + return f1 > f2; + } +}; + +// Multi_index tag names +struct descendant_score {}; +struct entry_time {}; +struct mining_score {}; +struct ancestor_score {}; + class CBlockPolicyEstimator; /** An inpoint - a combination of a transaction and an index n into its vin */ @@ -350,18 +425,27 @@ public: boost::multi_index::ordered_unique<mempoolentry_txid>, // sorted by fee rate boost::multi_index::ordered_non_unique< + boost::multi_index::tag<descendant_score>, boost::multi_index::identity<CTxMemPoolEntry>, CompareTxMemPoolEntryByDescendantScore >, // sorted by entry time boost::multi_index::ordered_non_unique< + boost::multi_index::tag<entry_time>, boost::multi_index::identity<CTxMemPoolEntry>, CompareTxMemPoolEntryByEntryTime - >, + >, // sorted by score (for mining prioritization) boost::multi_index::ordered_unique< + boost::multi_index::tag<mining_score>, boost::multi_index::identity<CTxMemPoolEntry>, CompareTxMemPoolEntryByScore + >, + // sorted by fee rate with ancestors + boost::multi_index::ordered_non_unique< + boost::multi_index::tag<ancestor_score>, + boost::multi_index::identity<CTxMemPoolEntry>, + CompareTxMemPoolEntryByAncestorFee > > > indexed_transaction_set; @@ -420,7 +504,7 @@ public: bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true); bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate = true); - void remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false); + void removeRecursive(const CTransaction &tx, std::list<CTransaction>& removed); void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags); void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed); void removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight, @@ -445,8 +529,12 @@ public: public: /** Remove a set of transactions from the mempool. * If a transaction is in this set, then all in-mempool descendants must - * also be in the set.*/ - void RemoveStaged(setEntries &stage); + * also be in the set, unless this transaction is being removed for being + * in a block. + * Set updateDescendants to true when removing a tx that was in a block, so + * that any in-mempool descendants have their ancestor state updated. + */ + void RemoveStaged(setEntries &stage, bool updateDescendants); /** When adding transactions from a disconnected block back to the mempool, * new mempool entries may have children in the mempool (which is generally @@ -469,7 +557,7 @@ public: * fSearchForParents = whether to search a tx's vin for in-mempool parents, or * look up parents from mapLinks. Must be true for entries not in the mempool */ - bool CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents = true); + bool CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents = true) const; /** Populate setDescendants with all in-mempool descendants of hash. * Assumes that setDescendants includes all in-mempool descendants of anything @@ -512,6 +600,7 @@ public: } bool lookup(uint256 hash, CTransaction& result) const; + bool lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const; /** Estimate fee rate needed to get into the next nBlocks * If no answer can be given at nBlocks, return an estimate @@ -547,21 +636,21 @@ private: * updated and hence their state is already reflected in the parent * state). * - * If updating an entry requires looking at more than maxDescendantsToVisit - * transactions, outside of the ones in setExclude, then give up. - * * cachedDescendants will be updated with the descendants of the transaction * being updated, so that future invocations don't need to walk the * same transaction again, if encountered in another transaction chain. */ - bool UpdateForDescendants(txiter updateIt, - int maxDescendantsToVisit, + void UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set<uint256> &setExclude); /** Update ancestors of hash to add/remove it as a descendant transaction. */ void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors); - /** For each transaction being removed, update ancestors and any direct children. */ - void UpdateForRemoveFromMempool(const setEntries &entriesToRemove); + /** Set ancestor state for an entry */ + void UpdateEntryForAncestors(txiter it, const setEntries &setAncestors); + /** For each transaction being removed, update ancestors and any direct children. + * If updateDescendants is true, then also update in-mempool descendants' + * ancestor state. */ + void UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants); /** Sever link between specified transaction and direct children. */ void UpdateChildrenForRemoval(txiter entry); diff --git a/src/ui_interface.h b/src/ui_interface.h index 967d243270..0b51d52e65 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -83,10 +83,9 @@ public: boost::signals2::signal<void (int newNumConnections)> NotifyNumConnectionsChanged; /** - * New, updated or cancelled alert. - * @note called with lock cs_mapAlerts held. + * Status bar alerts changed. */ - boost::signals2::signal<void (const uint256 &hash, ChangeType status)> NotifyAlertChanged; + boost::signals2::signal<void ()> NotifyAlertChanged; /** A wallet has been loaded. */ boost::signals2::signal<void (CWallet* wallet)> LoadWallet; diff --git a/src/uint256.h b/src/uint256.h index 4495000f2f..bcdb6dd7c2 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -42,9 +42,11 @@ public: memset(data, 0, sizeof(data)); } - friend inline bool operator==(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) == 0; } - friend inline bool operator!=(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) != 0; } - friend inline bool operator<(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) < 0; } + inline int Compare(const base_blob& other) const { return memcmp(data, other.data, sizeof(data)); } + + friend inline bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; } + friend inline bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; } + friend inline bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; } std::string GetHex() const; void SetHex(const char* psz); diff --git a/src/util.cpp b/src/util.cpp index 492697e12f..59f58f2c55 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -738,28 +738,6 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) } #endif -boost::filesystem::path GetTempPath() { -#if BOOST_FILESYSTEM_VERSION == 3 - return boost::filesystem::temp_directory_path(); -#else - // TODO: remove when we don't support filesystem v2 anymore - boost::filesystem::path path; -#ifdef WIN32 - char pszPath[MAX_PATH] = ""; - - if (GetTempPathA(MAX_PATH, pszPath)) - path = boost::filesystem::path(pszPath); -#else - path = boost::filesystem::path("/tmp"); -#endif - if (path.empty() || !boost::filesystem::is_directory(path)) { - LogPrintf("GetTempPath(): failed to find temp path\n"); - return boost::filesystem::path(""); - } - return path; -#endif -} - void runCommand(const std::string& strCommand) { int nErr = ::system(strCommand.c_str()); diff --git a/src/util.h b/src/util.h index 9da8fdf87a..ac099f1184 100644 --- a/src/util.h +++ b/src/util.h @@ -133,7 +133,6 @@ void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif -boost::filesystem::path GetTempPath(); void OpenDebugLog(); void ShrinkDebugFile(); void runCommand(const std::string& strCommand); diff --git a/src/version.h b/src/version.h index f7cf18d0b6..0e1d8a63ce 100644 --- a/src/version.h +++ b/src/version.h @@ -9,7 +9,7 @@ * network protocol versioning */ -static const int PROTOCOL_VERSION = 70012; +static const int PROTOCOL_VERSION = 70013; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; @@ -24,10 +24,6 @@ static const int MIN_PEER_PROTO_VERSION = GETHEADERS_VERSION; //! if possible, avoid requesting addresses nodes older than this static const int CADDR_TIME_VERSION = 31402; -//! only request blocks from nodes outside this range of versions -static const int NOBLKS_VERSION_START = 32000; -static const int NOBLKS_VERSION_END = 32400; - //! BIP 0031, pong message, is enabled for all versions AFTER this one static const int BIP0031_VERSION = 60000; @@ -40,4 +36,7 @@ static const int NO_BLOOM_VERSION = 70011; //! "sendheaders" command and announcing blocks with headers starts with this version static const int SENDHEADERS_VERSION = 70012; +//! "feefilter" tells peers to filter invs to you by fee starts with this version +static const int FEEFILTER_VERSION = 70013; + #endif // BITCOIN_VERSION_H diff --git a/src/versionbits.cpp b/src/versionbits.cpp new file mode 100644 index 0000000000..fbb60c0fc5 --- /dev/null +++ b/src/versionbits.cpp @@ -0,0 +1,133 @@ +// Copyright (c) 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. + +#include "versionbits.h" + +ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const +{ + int nPeriod = Period(params); + int nThreshold = Threshold(params); + int64_t nTimeStart = BeginTime(params); + int64_t nTimeTimeout = EndTime(params); + + // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1. + if (pindexPrev != NULL) { + pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod)); + } + + // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known + std::vector<const CBlockIndex*> vToCompute; + while (cache.count(pindexPrev) == 0) { + if (pindexPrev == NULL) { + // The genesis block is by definition defined. + cache[pindexPrev] = THRESHOLD_DEFINED; + break; + } + if (pindexPrev->GetMedianTimePast() < nTimeStart) { + // Optimizaton: don't recompute down further, as we know every earlier block will be before the start time + cache[pindexPrev] = THRESHOLD_DEFINED; + break; + } + vToCompute.push_back(pindexPrev); + pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod); + } + + // At this point, cache[pindexPrev] is known + assert(cache.count(pindexPrev)); + ThresholdState state = cache[pindexPrev]; + + // Now walk forward and compute the state of descendants of pindexPrev + while (!vToCompute.empty()) { + ThresholdState stateNext = state; + pindexPrev = vToCompute.back(); + vToCompute.pop_back(); + + switch (state) { + case THRESHOLD_DEFINED: { + if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { + stateNext = THRESHOLD_FAILED; + } else if (pindexPrev->GetMedianTimePast() >= nTimeStart) { + stateNext = THRESHOLD_STARTED; + } + break; + } + case THRESHOLD_STARTED: { + if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { + stateNext = THRESHOLD_FAILED; + break; + } + // We need to count + const CBlockIndex* pindexCount = pindexPrev; + int count = 0; + for (int i = 0; i < nPeriod; i++) { + if (Condition(pindexCount, params)) { + count++; + } + pindexCount = pindexCount->pprev; + } + if (count >= nThreshold) { + stateNext = THRESHOLD_LOCKED_IN; + } + break; + } + case THRESHOLD_LOCKED_IN: { + // Always progresses into ACTIVE. + stateNext = THRESHOLD_ACTIVE; + break; + } + case THRESHOLD_FAILED: + case THRESHOLD_ACTIVE: { + // Nothing happens, these are terminal states. + break; + } + } + cache[pindexPrev] = state = stateNext; + } + + return state; +} + +namespace +{ +/** + * Class to implement versionbits logic. + */ +class VersionBitsConditionChecker : public AbstractThresholdConditionChecker { +private: + const Consensus::DeploymentPos id; + +protected: + int64_t BeginTime(const Consensus::Params& params) const { return params.vDeployments[id].nStartTime; } + int64_t EndTime(const Consensus::Params& params) const { return params.vDeployments[id].nTimeout; } + int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; } + int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; } + + bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const + { + return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0); + } + +public: + VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {} + uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; } +}; + +} + +ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache) +{ + return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]); +} + +uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos) +{ + return VersionBitsConditionChecker(pos).Mask(params); +} + +void VersionBitsCache::Clear() +{ + for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) { + caches[d].clear(); + } +} diff --git a/src/versionbits.h b/src/versionbits.h new file mode 100644 index 0000000000..04f4738272 --- /dev/null +++ b/src/versionbits.h @@ -0,0 +1,59 @@ +// Copyright (c) 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. + +#ifndef BITCOIN_CONSENSUS_VERSIONBITS +#define BITCOIN_CONSENSUS_VERSIONBITS + +#include "chain.h" +#include <map> + +/** What block version to use for new blocks (pre versionbits) */ +static const int32_t VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4; +/** What bits to set in version for versionbits blocks */ +static const int32_t VERSIONBITS_TOP_BITS = 0x20000000UL; +/** What bitmask determines whether versionbits is in use */ +static const int32_t VERSIONBITS_TOP_MASK = 0xE0000000UL; +/** Total bits available for versionbits */ +static const int32_t VERSIONBITS_NUM_BITS = 29; + +enum ThresholdState { + THRESHOLD_DEFINED, + THRESHOLD_STARTED, + THRESHOLD_LOCKED_IN, + THRESHOLD_ACTIVE, + THRESHOLD_FAILED, +}; + +// A map that gives the state for blocks whose height is a multiple of Period(). +// The map is indexed by the block's parent, however, so all keys in the map +// will either be NULL or a block with (height + 1) % Period() == 0. +typedef std::map<const CBlockIndex*, ThresholdState> ThresholdConditionCache; + +/** + * Abstract class that implements BIP9-style threshold logic, and caches results. + */ +class AbstractThresholdConditionChecker { +protected: + virtual bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const =0; + virtual int64_t BeginTime(const Consensus::Params& params) const =0; + virtual int64_t EndTime(const Consensus::Params& params) const =0; + virtual int Period(const Consensus::Params& params) const =0; + virtual int Threshold(const Consensus::Params& params) const =0; + +public: + // Note that the function below takes a pindexPrev as input: they compute information for block B based on its parent. + ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const; +}; + +struct VersionBitsCache +{ + ThresholdConditionCache caches[Consensus::MAX_VERSION_BITS_DEPLOYMENTS]; + + void Clear(); +}; + +ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache); +uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos); + +#endif diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 6af5413a9e..c906785e9e 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -165,6 +165,11 @@ CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFu return (fRecovered ? RECOVER_OK : RECOVER_FAIL); } +/* End of headers, beginning of key/value data */ +static const char *HEADER_END = "HEADER=END"; +/* End of key/value data */ +static const char *DATA_END = "DATA=END"; + bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<CDBEnv::KeyValPair>& vResult) { LOCK(cs_db); @@ -199,18 +204,29 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<C // DATA=END string strLine; - while (!strDump.eof() && strLine != "HEADER=END") + while (!strDump.eof() && strLine != HEADER_END) getline(strDump, strLine); // Skip past header std::string keyHex, valueHex; - while (!strDump.eof() && keyHex != "DATA=END") { + while (!strDump.eof() && keyHex != DATA_END) { getline(strDump, keyHex); - if (keyHex != "DATA=END") { + if (keyHex != DATA_END) { + if (strDump.eof()) + break; getline(strDump, valueHex); + if (valueHex == DATA_END) { + LogPrintf("CDBEnv::Salvage: WARNING: Number of keys in data does not match number of values.\n"); + break; + } vResult.push_back(make_pair(ParseHex(keyHex), ParseHex(valueHex))); } } + if (keyHex != DATA_END) { + LogPrintf("CDBEnv::Salvage: WARNING: Unexpected end of file while reading salvage output.\n"); + return false; + } + return (result == 0); } diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 9ec28e7b91..6e50f92428 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -192,7 +192,7 @@ UniValue importaddress(const UniValue& params, bool fHelp) "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n" "4. p2sh (boolean, optional, default=false) Add the P2SH version of the script as well\n" "\nNote: This call can take minutes to complete if rescan is true.\n" - "If you have the full public key, you should call importpublickey instead of this.\n" + "If you have the full public key, you should call importpubkey instead of this.\n" "\nExamples:\n" "\nImport a script with rescan\n" + HelpExampleCli("importaddress", "\"myscript\"") + diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index f54ceb689c..1d23505961 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -394,7 +394,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr throw JSONRPCError(RPC_WALLET_ERROR, strError); } if (!pwalletMain->CommitTransaction(wtxNew, reservekey)) - throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); + throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here."); } UniValue sendtoaddress(const UniValue& params, bool fHelp) @@ -1346,6 +1346,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe entry.push_back(Pair("fee", ValueFromAmount(-nFee))); if (fLong) WalletTxToJSON(wtx, entry); + entry.push_back(Pair("abandoned", wtx.isAbandoned())); ret.push_back(entry); } } @@ -1827,7 +1828,7 @@ UniValue backupwallet(const UniValue& params, bool fHelp) if (fHelp || params.size() != 1) throw runtime_error( "backupwallet \"destination\"\n" - "\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n" + "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n" "\nArguments:\n" "1. \"destination\" (string) The destination directory or file\n" "\nExamples:\n" @@ -2098,16 +2099,17 @@ UniValue lockunspent(const UniValue& params, bool fHelp) if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( - "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n" + "lockunspent unlock ([{\"txid\":\"txid\",\"vout\":n},...])\n" "\nUpdates list of temporarily unspendable outputs.\n" "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" + "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n" "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n" "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n" "is always cleared (by virtue of process exit) when a node stops or fails.\n" "Also see the listunspent call\n" "\nArguments:\n" "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n" - "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n" + "2. \"transactions\" (string, optional) A json array of objects. Each object the txid (string) vout (numeric)\n" " [ (json array of json objects)\n" " {\n" " \"txid\":\"id\", (string) The transaction id\n" diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 65defc30aa..7d1928dd6a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -33,14 +33,14 @@ using namespace std; -/** - * Settings - */ +/** Transaction fee set by the user */ CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET; bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE; bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS; +const char * DEFAULT_WALLET_DAT = "wallet.dat"; + /** * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) * Override with -mintxfee @@ -399,13 +399,14 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover); if (r == CDBEnv::RECOVER_OK) { - warningString += strprintf(_("Warning: wallet.dat corrupt, data salvaged!" - " Original wallet.dat saved as wallet.{timestamp}.bak in %s; if" - " your balance or transactions are incorrect you should" - " restore from a backup."), GetDataDir()); + warningString += strprintf(_("Warning: Wallet file corrupt, data salvaged!" + " Original %s saved as %s in %s; if" + " your balance or transactions are incorrect you should" + " restore from a backup."), + walletFile, "wallet.{timestamp}.bak", GetDataDir()); } if (r == CDBEnv::RECOVER_FAIL) - errorString += _("wallet.dat corrupt, salvage failed"); + errorString += strprintf(_("%s corrupt, salvage failed"), walletFile); } return true; @@ -1265,9 +1266,11 @@ bool CWalletTx::RelayWalletTransaction() assert(pwallet->GetBroadcastTransactions()); if (!IsCoinBase()) { - if (GetDepthInMainChain() == 0 && !isAbandoned()) { + if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) { LogPrintf("Relaying wtx %s\n", GetHash().ToString()); - RelayTransaction((CTransaction)*this); + CFeeRate feeRate; + mempool.lookupFeeRate(GetHash(), feeRate); + RelayTransaction((CTransaction)*this, feeRate); return true; } } @@ -1577,7 +1580,7 @@ CAmount CWallet::GetUnconfirmedBalance() const for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; - if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0)) + if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool()) nTotal += pcoin->GetAvailableCredit(); } } @@ -1622,7 +1625,7 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; - if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0)) + if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool()) nTotal += pcoin->GetAvailableWatchOnlyCredit(); } } @@ -1667,6 +1670,11 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const if (nDepth < 0) continue; + // We should not consider coins which aren't at least in our mempool + // It's possible for these to be conflicted via ancestors which we may never be able to detect + if (nDepth == 0 && !pcoin->InMempool()) + continue; + for (unsigned int i = 0; i < pcoin->vout.size(); i++) { isminetype mine = IsMine(pcoin->vout[i]); if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && @@ -1838,10 +1846,9 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int return true; } -bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const +bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const { - vector<COutput> vCoins; - AvailableCoins(vCoins, true, coinControl); + vector<COutput> vCoins(vAvailableCoins); // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs) @@ -2007,6 +2014,9 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt { LOCK2(cs_main, cs_wallet); { + std::vector<COutput> vAvailableCoins; + AvailableCoins(vAvailableCoins, true, coinControl); + nFeeRet = 0; // Start with no fee and loop until there is enough fee while (true) @@ -2056,7 +2066,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt // Choose coins to use set<pair<const CWalletTx*,unsigned int> > setCoins; CAmount nValueIn = 0; - if (!SelectCoins(nValueToSelect, setCoins, nValueIn, coinControl)) + if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl)) { strFailReason = _("Insufficient funds"); return false; @@ -2956,6 +2966,203 @@ bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, st return false; } +std::string CWallet::GetWalletHelpString(bool showDebug) +{ + std::string strUsage = HelpMessageGroup(_("Wallet options:")); + strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); + strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE)); + strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"), + CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE))); + strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"), + CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE))); + strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), + CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); + strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup")); + strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup")); + if (showDebug) + strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS)); + strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE)); + strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET)); + strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup")); + strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT)); + strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST)); + strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); + strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") + + " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)")); + + if (showDebug) + { + strUsage += HelpMessageGroup(_("Wallet debugging/testing options:")); + + strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE)); + strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET)); + strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB)); + } + + return strUsage; +} + +CWallet* CWallet::InitLoadWallet(bool fDisableWallet, const std::string& strWalletFile, std::string& warningString, std::string& errorString) +{ + // needed to restore wallet transaction meta data after -zapwallettxes + std::vector<CWalletTx> vWtx; + + if (GetBoolArg("-zapwallettxes", false)) { + uiInterface.InitMessage(_("Zapping all transactions from wallet...")); + + CWallet *tempWallet = new CWallet(strWalletFile); + DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx); + if (nZapWalletRet != DB_LOAD_OK) { + errorString = strprintf(_("Error loading %s: Wallet corrupted"), strWalletFile); + uiInterface.InitMessage(strprintf(_("Error loading %s: Wallet corrupted"), strWalletFile)); + return NULL; + } + + delete tempWallet; + tempWallet = NULL; + } + + uiInterface.InitMessage(_("Loading wallet...")); + + int64_t nStart = GetTimeMillis(); + bool fFirstRun = true; + CWallet *walletInstance = new CWallet(strWalletFile); + DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun); + if (nLoadWalletRet != DB_LOAD_OK) + { + if (nLoadWalletRet == DB_CORRUPT) + errorString += strprintf(_("Error loading %s: Wallet corrupted"), strWalletFile) + "\n"; + else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) + { + warningString += strprintf(_("Error reading %s! All keys read correctly, but transaction data" + " or address book entries might be missing or incorrect."), + strWalletFile); + } + else if (nLoadWalletRet == DB_TOO_NEW) + errorString += strprintf(_("Error loading %s: Wallet requires newer version of %s"), + strWalletFile, _(PACKAGE_NAME)) + + "\n"; + else if (nLoadWalletRet == DB_NEED_REWRITE) + { + errorString += strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)) + "\n"; + LogPrintf("%s", errorString); + } + else + errorString += strprintf(_("Error loading %s"), strWalletFile) + "\n"; + + if (!errorString.empty()) + return NULL; + } + + if (GetBoolArg("-upgradewallet", fFirstRun)) + { + int nMaxVersion = GetArg("-upgradewallet", 0); + if (nMaxVersion == 0) // the -upgradewallet without argument case + { + LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST); + nMaxVersion = CLIENT_VERSION; + walletInstance->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately + } + else + LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion); + if (nMaxVersion < walletInstance->GetVersion()) + { + errorString += _("Cannot downgrade wallet") + "\n"; + return NULL; + } + walletInstance->SetMaxVersion(nMaxVersion); + } + + if (fFirstRun) + { + // Create new keyUser and set as default key + RandAddSeedPerfmon(); + + CPubKey newDefaultKey; + if (walletInstance->GetKeyFromPool(newDefaultKey)) { + walletInstance->SetDefaultKey(newDefaultKey); + if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) + { + errorString += _("Cannot write default address") += "\n"; + return NULL; + } + } + + walletInstance->SetBestChain(chainActive.GetLocator()); + } + + LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart); + + RegisterValidationInterface(walletInstance); + + CBlockIndex *pindexRescan = chainActive.Tip(); + if (GetBoolArg("-rescan", false)) + pindexRescan = chainActive.Genesis(); + else + { + CWalletDB walletdb(strWalletFile); + CBlockLocator locator; + if (walletdb.ReadBestBlock(locator)) + pindexRescan = FindForkInGlobalIndex(chainActive, locator); + else + pindexRescan = chainActive.Genesis(); + } + if (chainActive.Tip() && chainActive.Tip() != pindexRescan) + { + //We can't rescan beyond non-pruned blocks, stop and throw an error + //this might happen if a user uses a old wallet within a pruned node + // or if he ran -disablewallet for a longer time, then decided to re-enable + if (fPruneMode) + { + CBlockIndex *block = chainActive.Tip(); + while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block) + block = block->pprev; + + if (pindexRescan != block) + { + errorString = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"); + return NULL; + } + } + + uiInterface.InitMessage(_("Rescanning...")); + LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight); + nStart = GetTimeMillis(); + walletInstance->ScanForWalletTransactions(pindexRescan, true); + LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); + walletInstance->SetBestChain(chainActive.GetLocator()); + nWalletDBUpdated++; + + // Restore wallet transaction metadata after -zapwallettxes=1 + if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") + { + CWalletDB walletdb(strWalletFile); + + BOOST_FOREACH(const CWalletTx& wtxOld, vWtx) + { + uint256 hash = wtxOld.GetHash(); + std::map<uint256, CWalletTx>::iterator mi = walletInstance->mapWallet.find(hash); + if (mi != walletInstance->mapWallet.end()) + { + const CWalletTx* copyFrom = &wtxOld; + CWalletTx* copyTo = &mi->second; + copyTo->mapValue = copyFrom->mapValue; + copyTo->vOrderForm = copyFrom->vOrderForm; + copyTo->nTimeReceived = copyFrom->nTimeReceived; + copyTo->nTimeSmart = copyFrom->nTimeSmart; + copyTo->fFromMe = copyFrom->fFromMe; + copyTo->strFromAccount = copyFrom->strFromAccount; + copyTo->nOrderPos = copyFrom->nOrderPos; + copyTo->WriteToDisk(&walletdb); + } + } + } + } + walletInstance->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); + + return walletInstance; +} + CKeyPool::CKeyPool() { nTime = GetTime(); @@ -3033,5 +3240,5 @@ int CMerkleTx::GetBlocksToMaturity() const bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee) { CValidationState state; - return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee); + return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, NULL, false, nAbsurdFee); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 990b27c7ce..e37d972a15 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -55,6 +55,8 @@ static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2; static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000; static const bool DEFAULT_WALLETBROADCAST = true; +extern const char * DEFAULT_WALLET_DAT; + class CBlockIndex; class CCoinControl; class COutput; @@ -542,7 +544,7 @@ private: * all coins from coinControl are selected; Never select unconfirmed coins * if they are not ours */ - bool SelectCoins(const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const; + bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const; CWalletDB *pwalletdbEncryption; @@ -869,6 +871,12 @@ public: /* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */ bool AbandonTransaction(const uint256& hashTx); + + /* Returns the wallets help message */ + static std::string GetWalletHelpString(bool showDebug); + + /* initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */ + static CWallet* InitLoadWallet(bool fDisableWallet, const std::string& strWalletFile, std::string& warningString, std::string& errorString); }; /** A key allocated from the key pool. */ diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 67511976df..0a4a1dae2f 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -847,16 +847,16 @@ void ThreadFlushWalletDB(const string& strFile) map<string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile); if (mi != bitdb.mapFileUseCount.end()) { - LogPrint("db", "Flushing wallet.dat\n"); + LogPrint("db", "Flushing %s\n", strFile); nLastFlushed = nWalletDBUpdated; int64_t nStart = GetTimeMillis(); - // Flush wallet.dat so it's self contained + // Flush wallet file so it's self contained bitdb.CloseDb(strFile); bitdb.CheckpointLSN(strFile); bitdb.mapFileUseCount.erase(mi++); - LogPrint("db", "Flushed wallet.dat %dms\n", GetTimeMillis() - nStart); + LogPrint("db", "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart); } } } @@ -879,7 +879,7 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) bitdb.CheckpointLSN(wallet.strWalletFile); bitdb.mapFileUseCount.erase(wallet.strWalletFile); - // Copy wallet.dat + // Copy wallet file boost::filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile; boost::filesystem::path pathDest(strDest); if (boost::filesystem::is_directory(pathDest)) @@ -891,10 +891,10 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) #else boost::filesystem::copy_file(pathSrc, pathDest); #endif - LogPrintf("copied wallet.dat to %s\n", pathDest.string()); + LogPrintf("copied %s to %s\n", wallet.strWalletFile, pathDest.string()); return true; } catch (const boost::filesystem::filesystem_error& e) { - LogPrintf("error copying wallet.dat to %s - %s\n", pathDest.string(), e.what()); + LogPrintf("error copying %s to %s - %s\n", wallet.strWalletFile, pathDest.string(), e.what()); return false; } } @@ -905,15 +905,15 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) } // -// Try to (very carefully!) recover wallet.dat if there is a problem. +// Try to (very carefully!) recover wallet file if there is a problem. // bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys) { // Recovery procedure: - // move wallet.dat to wallet.timestamp.bak + // move wallet file to wallet.timestamp.bak // Call Salvage with fAggressive=true to // get as much data as possible. - // Rewrite salvaged data to wallet.dat + // Rewrite salvaged data to fresh wallet file // Set -rescan so any missing transactions will be // found. int64_t now = GetTime(); diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 8da33dead2..7e8cc4084e 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -73,7 +73,7 @@ public: } }; -/** Access to the wallet database (wallet.dat) */ +/** Access to the wallet database */ class CWalletDB : public CDB { public: diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index c8adcf8462..8705532429 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -100,7 +100,6 @@ bool CZMQNotificationInterface::Initialize() if (i!=notifiers.end()) { - Shutdown(); return false; } diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index ddc8fe93e9..f5839620ff 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -69,6 +69,7 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext) if (rc!=0) { zmqError("Failed to bind address"); + zmq_close(psocket); return false; } |