diff --git a/.gitignore b/.gitignore index 2a9f32c5..3d4bdf8a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,122 @@ *.user eccoin-qt.pro.user + +qa/pull-tester/run-bitcoind-for-test.sh +qa/pull-tester/tests_config.py +src/test/buildenv.py + +# imported from bitcoin/bitcoin + +*.tar.gz + +*.exe +src/bitcoin +src/bitcoind +src/bitcoin-cli +src/bitcoin-tx +src/test/test_bitcoin +src/test/test_bitcoin_fuzzy +src/qt/test/test_bitcoin-qt +src/build.h + +# autoreconf +Makefile.in +aclocal.m4 +autom4te.cache/ +build-aux/config.guess +build-aux/config.sub +build-aux/depcomp +build-aux/install-sh +build-aux/ltmain.sh +build-aux/m4/libtool.m4 +build-aux/m4/lt~obsolete.m4 +build-aux/m4/ltoptions.m4 +build-aux/m4/ltsugar.m4 +build-aux/m4/ltversion.m4 +build-aux/missing +build-aux/compile +build-aux/test-driver +config.log +config.status +configure +libtool +src/config/bitcoin-config.h +src/config/bitcoin-config.h.in +src/config/stamp-h1 +share/setup.nsi +share/qt/Info.plist + +src/univalue/gen + +src/qt/*.moc +src/qt/moc_*.cpp +src/qt/forms/ui_*.h + +src/qt/test/moc*.cpp + +.deps +.dirstamp +.libs +.*.swp +*.*~* +*.bak +*.rej +*.orig +*.pyc +*.o +*.o-* +*.patch +*.a +*.pb.cc +*.pb.h + +*.log +*.trs +*.dmg + +*.json.h +*.raw.h + +#libtool object files +*.lo +*.la + +# Compilation and Qt preprocessor part +*.qm +Makefile +bitcoin-qt +Bitcoin-Qt.app +background.tiff* + +# Unit-tests +Makefile.test +bitcoin-qt_test + +# Resources cpp +qrc_*.cpp + +# Mac specific +.DS_Store +build + +#lcov +*.gcno +*.gcda +/*.info +test_bitcoin.coverage/ +total.coverage/ +coverage_percent.txt + +#build tests +linux-coverage-build +linux-build +win32-build +test/config.ini +test/cache/* + +!src/leveldb*/Makefile + +/doc/doxygen/ + +libbitcoinconsensus.pc +contrib/devtools/split-debug.sh diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..1b708d0a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,79 @@ +sudo: required +dist: trusty +os: linux +language: generic +cache: + directories: + - depends/built + - depends/sdk-sources + - $HOME/.ccache +env: + global: + - MAKEJOBS=-j3 + - RUN_TESTS=false + - RUN_FORMATTING_CHECK=false + - CHECK_DOC=0 + - BOOST_TEST_RANDOM=1$TRAVIS_BUILD_ID + - CCACHE_SIZE=100M + - CCACHE_TEMPDIR=/tmp/.ccache-temp + - CCACHE_COMPRESS=1 + - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out + - SDK_URL=https://www.bitcoinunlimited.info/sdks + - PYTHON_DEBUG=1 + - WINEDEBUG=fixme-all + - PPA=ppa:bitcoin-unlimited/bu-ppa + matrix: +# bitcoind + - HOST=x86_64-unknown-linux-gnu PACKAGES="python3-zmq clang-format-3.8" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true RUN_FORMATTING_CHECK=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER" +# ARM64 + - HOST=aarch64-linux-gnu PACKAGES="g++-aarch64-linux-gnu" DEP_OPTS="NO_QT=1" GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" +# ARMHF + - 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" +# Win32 + - HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-i686 wine1.6 bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports" +# 32-bit + dash + - HOST=i686-pc-linux-gnu PACKAGES="g++-multilib bc python3-zmq" DEP_OPTS="NO_QT=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" USE_SHELL="/bin/dash" +# Win64 + - HOST=x86_64-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine1.6 bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports" +# x86_64 Linux, No wallet (uses qt5 dev package instead of depends Qt to speed up build and avoid timeout) + - HOST=x86_64-unknown-linux-gnu PACKAGES="python3 qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev" DEP_OPTS="NO_WALLET=1 NO_QT=1 ALLOW_HOST_PACKAGES=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" +# Cross-Mac + - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev" BITCOIN_CONFIG="--enable-reduce-exports" OSX_SDK=10.11 GOAL="deploy" +before_install: + - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g") + # temp fix with riak repo, by the way we don't need riak at all + - sudo rm -vf /etc/apt/sources.list.d/*riak* + - sudo apt-get update +install: + - if [ -n "$PPA" ]; then travis_retry sudo add-apt-repository "$PPA" -y; fi + - if [ -n "$DPKG_ADD_ARCH" ]; then sudo dpkg --add-architecture "$DPKG_ADD_ARCH" ; fi + - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi + - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq libdb4.8-dev libdb4.8++-dev $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 + - make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS +script: + - export TRAVIS_COMMIT_LOG=`git log --format=fuller -1` + - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi + - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST + - BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" + - depends/$HOST/native/bin/ccache --max-size=$CCACHE_SIZE + - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh 2>&1 > autogen.out"' || ./autogen.sh 2>&1 > autogen.out || ( cat autogen.out && false) + - mkdir build && cd build + - echo "BITCOIN_CONFIG_ALL=$BITCOIN_CONFIG_ALL" + - echo "BITCOIN_CONFIG=$BITCOIN_CONFIG" + - echo "GOAL=$GOAL" + - ../configure $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG > configure.out || ( cat configure.out && cat config.log && false) + - if [ "$RUN_FORMATTING_CHECK" = "true" ]; then make $MAKEJOBS check-formatting VERBOSE=1; fi + - stdbuf -i0 -o0 -e0 make $MAKEJOBS $GOAL 2>&1 | ../contrib/devtools/buildsilence.py || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false ) + - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib + - if [ "$RUN_TESTS" = "true" ] && { [ "$HOST" = "i686-w64-mingw32" ] || [ "$HOST" = "x86_64-w64-mingw32" ]; }; then travis_wait make $MAKEJOBS check VERBOSE=1; fi + - if [ "$RUN_TESTS" = "true" ] && ! { [ "$HOST" = "i686-w64-mingw32" ] || [ "$HOST" = "x86_64-w64-mingw32" ]; }; then make $MAKEJOBS check VERBOSE=1; fi + - if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py --coverage; fi +after_script: + - echo $TRAVIS_COMMIT_RANGE + - echo $TRAVIS_COMMIT_LOG diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..c1feb4ca --- /dev/null +++ b/Makefile.am @@ -0,0 +1,224 @@ +ACLOCAL_AMFLAGS = -I build-aux/m4 +SUBDIRS = src +.PHONY: deploy FORCE + +GZIP_ENV="-9n" + +if BUILD_BITCOIN_LIBS +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libbitcoinconsensus.pc +endif + +BITCOIND_BIN=$(top_builddir)/src/bitcoind$(EXEEXT) +BITCOIN_QT_BIN=$(top_builddir)/src/qt/bitcoin-qt$(EXEEXT) +BITCOIN_CLI_BIN=$(top_builddir)/src/bitcoin-cli$(EXEEXT) +BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT) + +OSX_APP=Bitcoin-Qt.app +OSX_DMG=Bitcoin-Core.dmg +OSX_BACKGROUND_IMAGE=background.tiff +OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus +OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist +OSX_BASE_LPROJ_DIR=$(top_srcdir)/contrib/macdeploy/Base.lproj/InfoPlist.strings +OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns +OSX_PLIST=$(top_srcdir)/share/qt/Info.plist #not installed +OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW + +BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \ + $(top_srcdir)/contrib/devtools/security-check.py + +WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \ + $(top_srcdir)/share/pixmaps/nsis-header.bmp \ + $(top_srcdir)/share/pixmaps/nsis-wizard.bmp \ + $(top_srcdir)/doc/README_windows.txt + +OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) $(OSX_BASE_LPROJ_DIR) \ + $(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) \ + $(top_srcdir)/contrib/macdeploy/DS_Store \ + $(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \ + $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh + +COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \ + leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \ + baseline_filtered.info block_test_filtered.info rpc_test.info rpc_test_filtered.info \ + leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info + +dist-hook: + -$(MAKE) -C $(top_distdir)/src/leveldb clean + -$(MAKE) -C $(top_distdir)/src/secp256k1 distclean + -$(GIT) archive --format=tar HEAD -- src/clientversion.cpp | $(AMTAR) -C $(top_distdir) -xf - + +distcheck-hook: + $(MKDIR_P) $(top_distdir)/_build/src/leveldb + cp -rf $(top_srcdir)/src/leveldb/* $(top_distdir)/_build/src/leveldb/ + -$(MAKE) -C $(top_distdir)/_build/src/leveldb clean + +distcleancheck: + @: + +$(BITCOIN_WIN_INSTALLER): all-recursive + $(MKDIR_P) $(top_builddir)/release + STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIND_BIN) $(top_builddir)/release + STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_QT_BIN) $(top_builddir)/release + STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_CLI_BIN) $(top_builddir)/release + @test -f $(MAKENSIS) && $(MAKENSIS) -V2 $(top_builddir)/share/setup.nsi || \ + echo error: could not build $@ + @echo built $@ + +$(if $(findstring src/,$(MAKECMDGOALS)),$(MAKECMDGOALS), none): FORCE + $(MAKE) -C src $(patsubst src/%,%,$@) + +$(OSX_APP)/Contents/PkgInfo: + $(MKDIR_P) $(@D) + @echo "APPL????" > $@ + +$(OSX_APP)/Contents/Resources/empty.lproj: + $(MKDIR_P) $(@D) + @touch $@ + +$(OSX_APP)/Contents/Info.plist: $(OSX_PLIST) + $(MKDIR_P) $(@D) + $(INSTALL_DATA) $< $@ + +$(OSX_APP)/Contents/Resources/bitcoin.icns: $(OSX_INSTALLER_ICONS) + $(MKDIR_P) $(@D) + $(INSTALL_DATA) $< $@ + +$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(BITCOIN_QT_BIN) + $(MKDIR_P) $(@D) + STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $< $@ + +$(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings: $(OSX_BASE_LPROJ_DIR) + $(MKDIR_P) $(@D) + $(INSTALL_DATA) $< $@ + +OSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lproj \ + $(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \ + $(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings + +if BUILD_DARWIN +$(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) + $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 + +deploydir: $(OSX_DMG) +else +APP_DIST_DIR=$(top_builddir)/dist +APP_DIST_EXTRAS=$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE) $(APP_DIST_DIR)/.DS_Store $(APP_DIST_DIR)/Applications + +$(APP_DIST_DIR)/Applications: + @rm -f $@ + @cd $(@D); $(LN_S) /Applications $(@F) + +$(APP_DIST_EXTRAS): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt + +$(OSX_DMG): $(APP_DIST_EXTRAS) + $(GENISOIMAGE) -no-cache-inodes -D -l -probe -V "Bitcoin-Core" -no-pad -r -dir-mode 0755 -apple -o $@ dist + +$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) + $(MKDIR_P) $(@D) + $(INSTALL) $< $@ +$(APP_DIST_DIR)/.DS_Store: contrib/macdeploy/DS_Store + $(INSTALL) $< $@ + +$(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) + INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2 + +deploydir: $(APP_DIST_EXTRAS) +endif + +if TARGET_DARWIN +appbundle: $(OSX_APP_BUILT) +deploy: $(OSX_DMG) +endif +if TARGET_WINDOWS +deploy: $(BITCOIN_WIN_INSTALLER) +endif + +$(BITCOIN_QT_BIN): FORCE + $(MAKE) -C src qt/$(@F) + +$(BITCOIND_BIN): FORCE + $(MAKE) -C src $(@F) + +$(BITCOIN_CLI_BIN): FORCE + $(MAKE) -C src $(@F) + +if USE_LCOV + +baseline.info: + $(LCOV) -c -i -d $(abs_builddir)/src -o $@ + +baseline_filtered.info: baseline.info + $(LCOV) -r $< "/usr/include/*" -o $@ + +leveldb_baseline.info: baseline_filtered.info + $(LCOV) -c -i -d $(abs_builddir)/src/leveldb -b $(abs_builddir)/src/leveldb -o $@ + +leveldb_baseline_filtered.info: leveldb_baseline.info + $(LCOV) -r $< "/usr/include/*" -o $@ + +baseline_filtered_combined.info: leveldb_baseline_filtered.info baseline_filtered.info + $(LCOV) -a leveldb_baseline_filtered.info -a baseline_filtered.info -o $@ + +test_bitcoin.info: baseline_filtered_combined.info + $(MAKE) -C src/ check + $(LCOV) -c -d $(abs_builddir)/src -t test_bitcoin -o $@ + $(LCOV) -z -d $(abs_builddir)/src + $(LCOV) -z -d $(abs_builddir)/src/leveldb + +test_bitcoin_filtered.info: test_bitcoin.info + $(LCOV) -r $< "/usr/include/*" -o $@ + +block_test.info: test_bitcoin_filtered.info + $(MKDIR_P) qa/tmp + qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool $(COMPARISON_TOOL_REORG_TESTS) + $(LCOV) -c -d $(abs_builddir)/src --t BitcoinJBlockTest -o $@ + $(LCOV) -z -d $(abs_builddir)/src + $(LCOV) -z -d $(abs_builddir)/src/leveldb + +block_test_filtered.info: block_test.info + $(LCOV) -r $< "/usr/include/*" -o $@ + +rpc_test.info: test_bitcoin_filtered.info + python qa/pull-tester/rpc-tests.py $(EXTENDED_RPC_TESTS) + $(LCOV) -c -d $(abs_builddir)/src --t rpc-tests -o $@ + $(LCOV) -z -d $(abs_builddir)/src + $(LCOV) -z -d $(abs_builddir)/src/leveldb + +rpc_test_filtered.info: rpc_test.info + $(LCOV) -r $< "/usr/include/*" -o $@ + +test_bitcoin_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info + $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -o $@ + +total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info block_test_filtered.info rpc_test_filtered.info + $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a block_test_filtered.info -a rpc_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt + +test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info + $(GENHTML) -s $< -o $(@D) + @touch $@ + +total.coverage/.dirstamp: total_coverage.info + $(GENHTML) -s $< -o $(@D) + @touch $@ + +cov: test_bitcoin.coverage/.dirstamp total.coverage/.dirstamp + +endif + +if USE_COMPARISON_TOOL +check-local: + $(MKDIR_P) qa/tmp + @qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool $(COMPARISON_TOOL_REORG_TESTS) 2>&1 +endif + +dist_noinst_SCRIPTS = autogen.sh + +EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.py qa/rpc-tests $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS) + +CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) + +.INTERMEDIATE: $(COVERAGE_INFO) + +clean-local: + rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ qa/tmp/ cache/ $(OSX_APP) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 00000000..3e26a183 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e +srcdir="$(dirname $0)" +cd "$srcdir" +if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then + LIBTOOLIZE="${GLIBTOOLIZE}" + export LIBTOOLIZE +fi +autoreconf --install --force --warnings=all diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4 new file mode 100644 index 00000000..715f16e4 --- /dev/null +++ b/build-aux/m4/ax_boost_base.m4 @@ -0,0 +1,291 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_boost_base.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# DESCRIPTION +# +# Test for the Boost C++ libraries of a particular version (or newer) +# +# If no path to the installed boost library is given the macro searchs +# under /usr, /usr/local, /opt and /opt/local and evaluates the +# $BOOST_ROOT environment variable. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS) +# +# And sets: +# +# HAVE_BOOST +# +# LICENSE +# +# Copyright (c) 2008 Thomas Porschberg +# Copyright (c) 2009 Peter Adolphs +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 27 + +AC_DEFUN([AX_BOOST_BASE], +[ +AC_ARG_WITH([boost], + [AS_HELP_STRING([--with-boost@<:@=ARG@:>@], + [use Boost library from a standard location (ARG=yes), + from the specified location (ARG=), + or disable it (ARG=no) + @<:@ARG=yes@:>@ ])], + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ac_boost_path="" + else + want_boost="yes" + ac_boost_path="$withval" + fi + ], + [want_boost="yes"]) + + +AC_ARG_WITH([boost-libdir], + AS_HELP_STRING([--with-boost-libdir=LIB_DIR], + [Force given directory for boost libraries. Note that this will override library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.]), + [ + if test -d "$withval" + then + ac_boost_lib_path="$withval" + else + AC_MSG_ERROR(--with-boost-libdir expected directory name) + fi + ], + [ac_boost_lib_path=""] +) + +if test "x$want_boost" = "xyes"; then + boost_lib_version_req=ifelse([$1], ,1.20.0,$1) + boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'` + boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'` + boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'` + boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + if test "x$boost_lib_version_req_sub_minor" = "x" ; then + boost_lib_version_req_sub_minor="0" + fi + WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor` + AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req) + succeeded=no + + dnl On 64-bit systems check for system libraries in both lib64 and lib. + dnl The former is specified by FHS, but e.g. Debian does not adhere to + dnl this (as it rises problems for generic multi-arch support). + dnl The last entry in the list is chosen by default when no libraries + dnl are found, e.g. when only header-only libraries are installed! + libsubdirs="lib" + ax_arch=`uname -m` + case $ax_arch in + x86_64) + libsubdirs="lib64 libx32 lib lib64" + ;; + ppc64|s390x|sparc64|aarch64|ppc64le) + libsubdirs="lib64 lib lib64" + ;; + esac + + dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give + dnl them priority over the other paths since, if libs are found there, they + dnl are almost assuredly the ones desired. + AC_REQUIRE([AC_CANONICAL_HOST]) + libsubdirs="lib/${host_cpu}-${host_os} $libsubdirs" + + case ${host_cpu} in + i?86) + libsubdirs="lib/i386-${host_os} $libsubdirs" + ;; + esac + + dnl some arches may advertise a cpu type that doesn't line up with their + dnl prefix's cpu type. For example, uname may report armv7l while libs are + dnl installed to /usr/lib/arm-linux-gnueabihf. Try getting the compiler's + dnl value for an extra chance of finding the correct path. + libsubdirs="lib/`$CXX -dumpmachine 2>/dev/null` $libsubdirs" + + dnl first we check the system location for boost libraries + dnl this location ist chosen if boost libraries are installed with the --layout=system option + dnl or if you install boost with RPM + if test "$ac_boost_path" != ""; then + BOOST_CPPFLAGS="-I$ac_boost_path/include" + for ac_boost_path_tmp in $libsubdirs; do + if test -d "$ac_boost_path"/"$ac_boost_path_tmp" ; then + BOOST_LDFLAGS="-L$ac_boost_path/$ac_boost_path_tmp" + break + fi + done + elif test "$cross_compiling" != yes; then + for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then + for libsubdir in $libsubdirs ; do + if ls "$ac_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$ac_boost_path_tmp/$libsubdir" + BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include" + break; + fi + done + fi + + dnl overwrite ld flags if we have required special directory with + dnl --with-boost-libdir parameter + if test "$ac_boost_lib_path" != ""; then + BOOST_LDFLAGS="-L$ac_boost_lib_path" + fi + + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_REQUIRE([AC_PROG_CXX]) + AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + @%:@include + ]], [[ + #if BOOST_VERSION >= $WANT_BOOST_VERSION + // Everything is okay + #else + # error Boost version is too old + #endif + ]])],[ + AC_MSG_RESULT(yes) + succeeded=yes + found_system=yes + ],[: + ]) + AC_LANG_POP([C++]) + + + + dnl if we found no boost with system layout we search for boost libraries + dnl built and installed without the --layout=system option or for a staged(not installed) version + if test "x$succeeded" != "xyes"; then + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + BOOST_CPPFLAGS= + BOOST_LDFLAGS= + _version=0 + if test "$ac_boost_path" != ""; then + if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then + for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "$V_CHECK" = "1" ; then + _version=$_version_tmp + fi + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" + done + dnl if nothing found search for layout used in Windows distributions + if test -z "$BOOST_CPPFLAGS"; then + if test -d "$ac_boost_path/boost" && test -r "$ac_boost_path/boost"; then + BOOST_CPPFLAGS="-I$ac_boost_path" + fi + fi + fi + else + if test "$cross_compiling" != yes; then + for ac_boost_path in /usr /usr/local /opt /opt/local ; do + if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then + for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "$V_CHECK" = "1" ; then + _version=$_version_tmp + best_path=$ac_boost_path + fi + done + fi + done + + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" + if test "$ac_boost_lib_path" = ""; then + for libsubdir in $libsubdirs ; do + if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$best_path/$libsubdir" + fi + fi + + if test "x$BOOST_ROOT" != "x"; then + for libsubdir in $libsubdirs ; do + if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then + version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` + stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` + stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` + V_CHECK=`expr $stage_version_shorten \>\= $_version` + if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then + AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) + BOOST_CPPFLAGS="-I$BOOST_ROOT" + BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir" + fi + fi + fi + fi + + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + @%:@include + ]], [[ + #if BOOST_VERSION >= $WANT_BOOST_VERSION + // Everything is okay + #else + # error Boost version is too old + #endif + ]])],[ + AC_MSG_RESULT(yes) + succeeded=yes + found_system=yes + ],[: + ]) + AC_LANG_POP([C++]) + fi + + if test "$succeeded" != "yes" ; then + if test "$_version" = "0" ; then + AC_MSG_NOTICE([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation.]]) + else + AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) + fi + # execute ACTION-IF-NOT-FOUND (if present): + ifelse([$3], , :, [$3]) + else + AC_SUBST(BOOST_CPPFLAGS) + AC_SUBST(BOOST_LDFLAGS) + AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) + # execute ACTION-IF-FOUND (if present): + ifelse([$2], , :, [$2]) + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" +fi + +]) diff --git a/build-aux/m4/ax_boost_chrono.m4 b/build-aux/m4/ax_boost_chrono.m4 new file mode 100644 index 00000000..318ecea1 --- /dev/null +++ b/build-aux/m4/ax_boost_chrono.m4 @@ -0,0 +1,119 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_boost_chrono.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_CHRONO +# +# DESCRIPTION +# +# Test for System library from the Boost C++ libraries. The macro requires +# a preceding call to AX_BOOST_BASE. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_CHRONO_LIB) +# +# And sets: +# +# HAVE_BOOST_CHRONO +# +# LICENSE +# +# Copyright (c) 2012 Xiyue Deng +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +AC_DEFUN([AX_BOOST_CHRONO], +[ + AC_ARG_WITH([boost-chrono], + AS_HELP_STRING([--with-boost-chrono@<:@=special-lib@:>@], + [use the Chrono library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-chrono=boost_chrono-gcc-mt ]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_chrono_lib="" + else + want_boost="yes" + ax_boost_user_chrono_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_BUILD]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_CACHE_CHECK(whether the Boost::Chrono library is available, + ax_cv_boost_chrono, + [AC_LANG_PUSH([C++]) + CXXFLAGS_SAVE=$CXXFLAGS + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], + [[boost::chrono::system_clock::time_point time;]])], + ax_cv_boost_chrono=yes, ax_cv_boost_chrono=no) + CXXFLAGS=$CXXFLAGS_SAVE + AC_LANG_POP([C++]) + ]) + if test "x$ax_cv_boost_chrono" = "xyes"; then + AC_SUBST(BOOST_CPPFLAGS) + + AC_DEFINE(HAVE_BOOST_CHRONO,,[define if the Boost::Chrono library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + + LDFLAGS_SAVE=$LDFLAGS + if test "x$ax_boost_user_chrono_lib" = "x"; then + ax_lib= + for libextension in `ls $BOOSTLIBDIR/libboost_chrono*.so* $BOOSTLIBDIR/libboost_chrono*.dylib* $BOOSTLIBDIR/libboost_chrono*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_chrono.*\)\.so.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], + [link_chrono="no"]) + done + if test "x$link_chrono" != "xyes"; then + for libextension in `ls $BOOSTLIBDIR/boost_chrono*.dll* $BOOSTLIBDIR/boost_chrono*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_chrono.*\)\.dll.*$;\1;' -e 's;^\(boost_chrono.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], + [link_chrono="no"]) + done + fi + + else + for ax_lib in $ax_boost_user_chrono_lib boost_chrono-$ax_boost_user_chrono_lib; do + AC_CHECK_LIB($ax_lib, exit, + [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], + [link_chrono="no"]) + done + + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the boost_chrono library!) + fi + if test "x$link_chrono" = "xno"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) diff --git a/build-aux/m4/ax_boost_filesystem.m4 b/build-aux/m4/ax_boost_filesystem.m4 new file mode 100644 index 00000000..f5c9d564 --- /dev/null +++ b/build-aux/m4/ax_boost_filesystem.m4 @@ -0,0 +1,119 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_boost_filesystem.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_FILESYSTEM +# +# DESCRIPTION +# +# Test for Filesystem library from the Boost C++ libraries. The macro +# requires a preceding call to AX_BOOST_BASE. Further documentation is +# available at . +# +# This macro calls: +# +# AC_SUBST(BOOST_FILESYSTEM_LIB) +# +# And sets: +# +# HAVE_BOOST_FILESYSTEM +# +# LICENSE +# +# Copyright (c) 2009 Thomas Porschberg +# Copyright (c) 2009 Michael Tindal +# Copyright (c) 2009 Roman Rybalko +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 26 + +AC_DEFUN([AX_BOOST_FILESYSTEM], +[ + AC_ARG_WITH([boost-filesystem], + AS_HELP_STRING([--with-boost-filesystem@<:@=special-lib@:>@], + [use the Filesystem library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-filesystem=boost_filesystem-gcc-mt ]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_filesystem_lib="" + else + want_boost="yes" + ax_boost_user_filesystem_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + LIBS_SAVED=$LIBS + LIBS="$LIBS $BOOST_SYSTEM_LIB" + export LIBS + + AC_CACHE_CHECK(whether the Boost::Filesystem library is available, + ax_cv_boost_filesystem, + [AC_LANG_PUSH([C++]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], + [[using namespace boost::filesystem; + path my_path( "foo/bar/data.txt" ); + return 0;]])], + ax_cv_boost_filesystem=yes, ax_cv_boost_filesystem=no) + AC_LANG_POP([C++]) + ]) + if test "x$ax_cv_boost_filesystem" = "xyes"; then + AC_DEFINE(HAVE_BOOST_FILESYSTEM,,[define if the Boost::Filesystem library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + ax_lib= + if test "x$ax_boost_user_filesystem_lib" = "x"; then + for libextension in `ls -r $BOOSTLIBDIR/libboost_filesystem* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break], + [link_filesystem="no"]) + done + if test "x$link_filesystem" != "xyes"; then + for libextension in `ls -r $BOOSTLIBDIR/boost_filesystem* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break], + [link_filesystem="no"]) + done + fi + else + for ax_lib in $ax_boost_user_filesystem_lib boost_filesystem-$ax_boost_user_filesystem_lib; do + AC_CHECK_LIB($ax_lib, exit, + [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break], + [link_filesystem="no"]) + done + + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the boost_filesystem library!) + fi + if test "x$link_filesystem" != "xyes"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + LIBS="$LIBS_SAVED" + fi +]) diff --git a/build-aux/m4/ax_boost_program_options.m4 b/build-aux/m4/ax_boost_program_options.m4 new file mode 100644 index 00000000..2bdb5937 --- /dev/null +++ b/build-aux/m4/ax_boost_program_options.m4 @@ -0,0 +1,108 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_boost_program_options.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_BOOST_PROGRAM_OPTIONS +# +# DESCRIPTION +# +# Test for program options library from the Boost C++ libraries. The macro +# requires a preceding call to AX_BOOST_BASE. Further documentation is +# available at . +# +# This macro calls: +# +# AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) +# +# And sets: +# +# HAVE_BOOST_PROGRAM_OPTIONS +# +# LICENSE +# +# Copyright (c) 2009 Thomas Porschberg +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 24 + +AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], +[ + AC_ARG_WITH([boost-program-options], + AS_HELP_STRING([--with-boost-program-options@<:@=special-lib@:>@], + [use the program options library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-program-options=boost_program_options-gcc-mt-1_33_1 ]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_program_options_lib="" + else + want_boost="yes" + ax_boost_user_program_options_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + export want_boost + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + AC_CACHE_CHECK([whether the Boost::Program_Options library is available], + ax_cv_boost_program_options, + [AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include + ]], + [[boost::program_options::error err("Error message"); + return 0;]])], + ax_cv_boost_program_options=yes, ax_cv_boost_program_options=no) + AC_LANG_POP([C++]) + ]) + if test "$ax_cv_boost_program_options" = yes; then + AC_DEFINE(HAVE_BOOST_PROGRAM_OPTIONS,,[define if the Boost::PROGRAM_OPTIONS library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + if test "x$ax_boost_user_program_options_lib" = "x"; then + for libextension in `ls $BOOSTLIBDIR/libboost_program_options*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.dylib* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.dylib.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break], + [link_program_options="no"]) + done + if test "x$link_program_options" != "xyes"; then + for libextension in `ls $BOOSTLIBDIR/boost_program_options*.dll* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.dll.*$;\1;'` `ls $BOOSTLIBDIR/boost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break], + [link_program_options="no"]) + done + fi + else + for ax_lib in $ax_boost_user_program_options_lib boost_program_options-$ax_boost_user_program_options_lib; do + AC_CHECK_LIB($ax_lib, main, + [BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break], + [link_program_options="no"]) + done + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the boost_program_options library!) + fi + if test "x$link_program_options" != "xyes"; then + AC_MSG_ERROR([Could not link against [$ax_lib] !]) + fi + fi + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) diff --git a/build-aux/m4/ax_boost_system.m4 b/build-aux/m4/ax_boost_system.m4 new file mode 100644 index 00000000..1c05450c --- /dev/null +++ b/build-aux/m4/ax_boost_system.m4 @@ -0,0 +1,122 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_boost_system.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_SYSTEM +# +# DESCRIPTION +# +# Test for System library from the Boost C++ libraries. The macro requires +# a preceding call to AX_BOOST_BASE. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_SYSTEM_LIB) +# +# And sets: +# +# HAVE_BOOST_SYSTEM +# +# LICENSE +# +# Copyright (c) 2008 Thomas Porschberg +# Copyright (c) 2008 Michael Tindal +# Copyright (c) 2008 Daniel Casimiro +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 18 + +AC_DEFUN([AX_BOOST_SYSTEM], +[ + AC_ARG_WITH([boost-system], + AS_HELP_STRING([--with-boost-system@<:@=special-lib@:>@], + [use the System library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-system=boost_system-gcc-mt ]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_system_lib="" + else + want_boost="yes" + ax_boost_user_system_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_BUILD]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_CACHE_CHECK(whether the Boost::System library is available, + ax_cv_boost_system, + [AC_LANG_PUSH([C++]) + CXXFLAGS_SAVE=$CXXFLAGS + CXXFLAGS= + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], + [[boost::system::error_category *a = 0;]])], + ax_cv_boost_system=yes, ax_cv_boost_system=no) + CXXFLAGS=$CXXFLAGS_SAVE + AC_LANG_POP([C++]) + ]) + if test "x$ax_cv_boost_system" = "xyes"; then + AC_SUBST(BOOST_CPPFLAGS) + + AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + + LDFLAGS_SAVE=$LDFLAGS + if test "x$ax_boost_user_system_lib" = "x"; then + ax_lib= + for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break], + [link_system="no"]) + done + if test "x$link_system" != "xyes"; then + for libextension in `ls -r $BOOSTLIBDIR/boost_system* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break], + [link_system="no"]) + done + fi + + else + for ax_lib in $ax_boost_user_system_lib boost_system-$ax_boost_user_system_lib; do + AC_CHECK_LIB($ax_lib, exit, + [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break], + [link_system="no"]) + done + + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the boost_system library!) + fi + if test "x$link_system" = "xno"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) diff --git a/build-aux/m4/ax_boost_thread.m4 b/build-aux/m4/ax_boost_thread.m4 new file mode 100644 index 00000000..9f0bd0b2 --- /dev/null +++ b/build-aux/m4/ax_boost_thread.m4 @@ -0,0 +1,150 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_boost_thread.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_THREAD +# +# DESCRIPTION +# +# Test for Thread library from the Boost C++ libraries. The macro requires +# a preceding call to AX_BOOST_BASE. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_THREAD_LIB) +# +# And sets: +# +# HAVE_BOOST_THREAD +# +# LICENSE +# +# Copyright (c) 2009 Thomas Porschberg +# Copyright (c) 2009 Michael Tindal +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 27 + +AC_DEFUN([AX_BOOST_THREAD], +[ + AC_ARG_WITH([boost-thread], + AS_HELP_STRING([--with-boost-thread@<:@=special-lib@:>@], + [use the Thread library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-thread=boost_thread-gcc-mt ]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_thread_lib="" + else + want_boost="yes" + ax_boost_user_thread_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_BUILD]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_CACHE_CHECK(whether the Boost::Thread library is available, + ax_cv_boost_thread, + [AC_LANG_PUSH([C++]) + CXXFLAGS_SAVE=$CXXFLAGS + + if test "x$host_os" = "xsolaris" ; then + CXXFLAGS="-pthreads $CXXFLAGS" + elif test "x$host_os" = "xmingw32" ; then + CXXFLAGS="-mthreads $CXXFLAGS" + else + CXXFLAGS="-pthread $CXXFLAGS" + fi + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], + [[boost::thread_group thrds; + return 0;]])], + ax_cv_boost_thread=yes, ax_cv_boost_thread=no) + CXXFLAGS=$CXXFLAGS_SAVE + AC_LANG_POP([C++]) + ]) + if test "x$ax_cv_boost_thread" = "xyes"; then + if test "x$host_os" = "xsolaris" ; then + BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS" + elif test "x$host_os" = "xmingw32" ; then + BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS" + else + BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS" + fi + + AC_SUBST(BOOST_CPPFLAGS) + + AC_DEFINE(HAVE_BOOST_THREAD,,[define if the Boost::Thread library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + + LDFLAGS_SAVE=$LDFLAGS + case "x$host_os" in + *bsd* ) + LDFLAGS="-pthread $LDFLAGS" + break; + ;; + esac + if test "x$ax_boost_user_thread_lib" = "x"; then + ax_lib= + for libextension in `ls -r $BOOSTLIBDIR/libboost_thread* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'`; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], + [link_thread="no"]) + done + if test "x$link_thread" != "xyes"; then + for libextension in `ls -r $BOOSTLIBDIR/boost_thread* 2>/dev/null | sed 's,.*/,,' | sed 's,\..*,,'`; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], + [link_thread="no"]) + done + fi + + else + for ax_lib in $ax_boost_user_thread_lib boost_thread-$ax_boost_user_thread_lib; do + AC_CHECK_LIB($ax_lib, exit, + [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], + [link_thread="no"]) + done + + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the boost_thread library!) + fi + if test "x$link_thread" = "xno"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + else + case "x$host_os" in + *bsd* ) + BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS" + break; + ;; + esac + + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) diff --git a/build-aux/m4/ax_boost_unit_test_framework.m4 b/build-aux/m4/ax_boost_unit_test_framework.m4 new file mode 100644 index 00000000..4efd1e2f --- /dev/null +++ b/build-aux/m4/ax_boost_unit_test_framework.m4 @@ -0,0 +1,138 @@ +# ================================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_boost_unit_test_framework.html +# ================================================================================ +# +# SYNOPSIS +# +# AX_BOOST_UNIT_TEST_FRAMEWORK +# +# DESCRIPTION +# +# Test for Unit_Test_Framework library from the Boost C++ libraries. The +# macro requires a preceding call to AX_BOOST_BASE. Further documentation +# is available at . +# +# This macro calls: +# +# AC_SUBST(BOOST_UNIT_TEST_FRAMEWORK_LIB) +# +# And sets: +# +# HAVE_BOOST_UNIT_TEST_FRAMEWORK +# +# LICENSE +# +# Copyright (c) 2008 Thomas Porschberg +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 19 + +AC_DEFUN([AX_BOOST_UNIT_TEST_FRAMEWORK], +[ + AC_ARG_WITH([boost-unit-test-framework], + AS_HELP_STRING([--with-boost-unit-test-framework@<:@=special-lib@:>@], + [use the Unit_Test_Framework library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-unit-test-framework=boost_unit_test_framework-gcc ]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_unit_test_framework_lib="" + else + want_boost="yes" + ax_boost_user_unit_test_framework_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_CACHE_CHECK(whether the Boost::Unit_Test_Framework library is available, + ax_cv_boost_unit_test_framework, + [AC_LANG_PUSH([C++]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], + [[using boost::unit_test::test_suite; + test_suite* test= BOOST_TEST_SUITE( "Unit test example 1" ); return 0;]])], + ax_cv_boost_unit_test_framework=yes, ax_cv_boost_unit_test_framework=no) + AC_LANG_POP([C++]) + ]) + if test "x$ax_cv_boost_unit_test_framework" = "xyes"; then + AC_DEFINE(HAVE_BOOST_UNIT_TEST_FRAMEWORK,,[define if the Boost::Unit_Test_Framework library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + + if test "x$ax_boost_user_unit_test_framework_lib" = "x"; then + saved_ldflags="${LDFLAGS}" + ax_lib= + for monitor_library in `ls $BOOSTLIBDIR/libboost_unit_test_framework*.so* $BOOSTLIBDIR/libboost_unit_test_framework*.dylib* $BOOSTLIBDIR/libboost_unit_test_framework*.a* 2>/dev/null` ; do + if test -r $monitor_library ; then + libextension=`echo $monitor_library | sed 's,.*/,,' | sed -e 's;^lib\(boost_unit_test_framework.*\)\.so.*$;\1;' -e 's;^lib\(boost_unit_test_framework.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_unit_test_framework.*\)\.a.*$;\1;'` + ax_lib=${libextension} + link_unit_test_framework="yes" + else + link_unit_test_framework="no" + fi + + if test "x$link_unit_test_framework" = "xyes"; then + BOOST_UNIT_TEST_FRAMEWORK_LIB="-l$ax_lib" + AC_SUBST(BOOST_UNIT_TEST_FRAMEWORK_LIB) + break + fi + done + if test "x$link_unit_test_framework" != "xyes"; then + for libextension in `ls $BOOSTLIBDIR/boost_unit_test_framework*.dll* $BOOSTLIBDIR/boost_unit_test_framework*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_unit_test_framework.*\)\.dll.*$;\1;' -e 's;^\(boost_unit_test_framework.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_UNIT_TEST_FRAMEWORK_LIB="-l$ax_lib"; AC_SUBST(BOOST_UNIT_TEST_FRAMEWORK_LIB) link_unit_test_framework="yes"; break], + [link_unit_test_framework="no"]) + done + fi + else + link_unit_test_framework="no" + saved_ldflags="${LDFLAGS}" + for ax_lib in boost_unit_test_framework-$ax_boost_user_unit_test_framework_lib $ax_boost_user_unit_test_framework_lib ; do + if test "x$link_unit_test_framework" = "xyes"; then + break; + fi + for unittest_library in `ls $BOOSTLIBDIR/lib${ax_lib}.so* $BOOSTLIBDIR/lib${ax_lib}.a* 2>/dev/null` ; do + if test -r $unittest_library ; then + libextension=`echo $unittest_library | sed 's,.*/,,' | sed -e 's;^lib\(boost_unit_test_framework.*\)\.so.*$;\1;' -e 's;^lib\(boost_unit_test_framework.*\)\.a*$;\1;'` + ax_lib=${libextension} + link_unit_test_framework="yes" + else + link_unit_test_framework="no" + fi + + if test "x$link_unit_test_framework" = "xyes"; then + BOOST_UNIT_TEST_FRAMEWORK_LIB="-l$ax_lib" + AC_SUBST(BOOST_UNIT_TEST_FRAMEWORK_LIB) + break + fi + done + done + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the boost_unit_test_framework library!) + fi + if test "x$link_unit_test_framework" != "xyes"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) diff --git a/build-aux/m4/ax_check_compile_flag.m4 b/build-aux/m4/ax_check_compile_flag.m4 new file mode 100644 index 00000000..ca363971 --- /dev/null +++ b/build-aux/m4/ax_check_compile_flag.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 4 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/build-aux/m4/ax_check_link_flag.m4 b/build-aux/m4/ax_check_link_flag.m4 new file mode 100644 index 00000000..eb01a6ce --- /dev/null +++ b/build-aux/m4/ax_check_link_flag.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the linker or gives an error. +# (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_LINK_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 4 + +AC_DEFUN([AX_CHECK_LINK_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ + ax_check_save_flags=$LDFLAGS + LDFLAGS="$LDFLAGS $4 $1" + AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + LDFLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_LINK_FLAGS diff --git a/build-aux/m4/ax_check_preproc_flag.m4 b/build-aux/m4/ax_check_preproc_flag.m4 new file mode 100644 index 00000000..ca1d5ee2 --- /dev/null +++ b/build-aux/m4/ax_check_preproc_flag.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_preproc_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_PREPROC_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's +# preprocessor or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the preprocessor's default +# flags when the check is done. The check is thus made with the flags: +# "CPPFLAGS EXTRA-FLAGS FLAG". This can for example be used to force the +# preprocessor to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_PREPROC_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{COMPILE,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 4 + +AC_DEFUN([AX_CHECK_PREPROC_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]cppflags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG preprocessor accepts $1], CACHEVAR, [ + ax_check_save_flags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $4 $1" + AC_PREPROC_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + CPPFLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_PREPROC_FLAGS diff --git a/build-aux/m4/ax_cxx_compile_stdcxx.m4 b/build-aux/m4/ax_cxx_compile_stdcxx.m4 new file mode 100644 index 00000000..2c18e49c --- /dev/null +++ b/build-aux/m4/ax_cxx_compile_stdcxx.m4 @@ -0,0 +1,562 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the specified +# version of the C++ standard. If necessary, add switches to CXX and +# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) +# or '14' (for the C++14 standard). +# +# The second argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The third argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline support for the specified C++ standard is +# required and that the macro should error out if no mode with that +# support is found. If specified 'optional', then configuration proceeds +# regardless, after defining HAVE_CXX${VERSION} if and only if a +# supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 4 + +dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro +dnl (serial version number 13). + +AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl + m4_if([$1], [11], [], + [$1], [14], [], + [$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])], + [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$2], [], [], + [$2], [ext], [], + [$2], [noext], [], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], + [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], + [$3], [optional], [ax_cxx_compile_cxx$1_required=false], + [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi + + m4_if([$2], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++$1 -std=gnu++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + fi]) + + m4_if([$2], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++11 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++11" + for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx$1_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) + fi + fi + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) + else + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) + fi + AC_SUBST(HAVE_CXX$1) +]) + + +dnl Test body for checking C++11 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 +) + + +dnl Test body for checking C++14 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 +) + + +dnl Tests for new features in C++11 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + +]]) + + +dnl Tests for new features in C++14 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_seperators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + +]]) diff --git a/build-aux/m4/ax_gcc_func_attribute.m4 b/build-aux/m4/ax_gcc_func_attribute.m4 new file mode 100644 index 00000000..c788ca9b --- /dev/null +++ b/build-aux/m4/ax_gcc_func_attribute.m4 @@ -0,0 +1,223 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_gcc_func_attribute.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_FUNC_ATTRIBUTE(ATTRIBUTE) +# +# DESCRIPTION +# +# This macro checks if the compiler supports one of GCC's function +# attributes; many other compilers also provide function attributes with +# the same syntax. Compiler warnings are used to detect supported +# attributes as unsupported ones are ignored by default so quieting +# warnings when using this macro will yield false positives. +# +# The ATTRIBUTE parameter holds the name of the attribute to be checked. +# +# If ATTRIBUTE is supported define HAVE_FUNC_ATTRIBUTE_. +# +# The macro caches its result in the ax_cv_have_func_attribute_ +# variable. +# +# The macro currently supports the following function attributes: +# +# alias +# aligned +# alloc_size +# always_inline +# artificial +# cold +# const +# constructor +# constructor_priority for constructor attribute with priority +# deprecated +# destructor +# dllexport +# dllimport +# error +# externally_visible +# flatten +# format +# format_arg +# gnu_inline +# hot +# ifunc +# leaf +# malloc +# noclone +# noinline +# nonnull +# noreturn +# nothrow +# optimize +# pure +# unused +# used +# visibility +# warning +# warn_unused_result +# weak +# weakref +# +# Unsuppored function attributes will be tested with a prototype returning +# an int and not accepting any arguments and the result of the check might +# be wrong or meaningless so use with care. +# +# LICENSE +# +# Copyright (c) 2013 Gabriele Svelto +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 3 + +AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ + AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1]) + + AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([ + m4_case([$1], + [alias], [ + int foo( void ) { return 0; } + int bar( void ) __attribute__(($1("foo"))); + ], + [aligned], [ + int foo( void ) __attribute__(($1(32))); + ], + [alloc_size], [ + void *foo(int a) __attribute__(($1(1))); + ], + [always_inline], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [artificial], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [cold], [ + int foo( void ) __attribute__(($1)); + ], + [const], [ + int foo( void ) __attribute__(($1)); + ], + [constructor_priority], [ + int foo( void ) __attribute__((__constructor__(65535/2))); + ], + [constructor], [ + int foo( void ) __attribute__(($1)); + ], + [deprecated], [ + int foo( void ) __attribute__(($1(""))); + ], + [destructor], [ + int foo( void ) __attribute__(($1)); + ], + [dllexport], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [dllimport], [ + int foo( void ) __attribute__(($1)); + ], + [error], [ + int foo( void ) __attribute__(($1(""))); + ], + [externally_visible], [ + int foo( void ) __attribute__(($1)); + ], + [flatten], [ + int foo( void ) __attribute__(($1)); + ], + [format], [ + int foo(const char *p, ...) __attribute__(($1(printf, 1, 2))); + ], + [format_arg], [ + char *foo(const char *p) __attribute__(($1(1))); + ], + [gnu_inline], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [hot], [ + int foo( void ) __attribute__(($1)); + ], + [ifunc], [ + int my_foo( void ) { return 0; } + static int (*resolve_foo(void))(void) { return my_foo; } + int foo( void ) __attribute__(($1("resolve_foo"))); + ], + [leaf], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [malloc], [ + void *foo( void ) __attribute__(($1)); + ], + [noclone], [ + int foo( void ) __attribute__(($1)); + ], + [noinline], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [nonnull], [ + int foo(char *p) __attribute__(($1(1))); + ], + [noreturn], [ + void foo( void ) __attribute__(($1)); + ], + [nothrow], [ + int foo( void ) __attribute__(($1)); + ], + [optimize], [ + __attribute__(($1(3))) int foo( void ) { return 0; } + ], + [pure], [ + int foo( void ) __attribute__(($1)); + ], + [unused], [ + int foo( void ) __attribute__(($1)); + ], + [used], [ + int foo( void ) __attribute__(($1)); + ], + [visibility], [ + int foo_def( void ) __attribute__(($1("default"))); + int foo_hid( void ) __attribute__(($1("hidden"))); + int foo_int( void ) __attribute__(($1("internal"))); + int foo_pro( void ) __attribute__(($1("protected"))); + ], + [warning], [ + int foo( void ) __attribute__(($1(""))); + ], + [warn_unused_result], [ + int foo( void ) __attribute__(($1)); + ], + [weak], [ + int foo( void ) __attribute__(($1)); + ], + [weakref], [ + static int foo( void ) { return 0; } + static int bar( void ) __attribute__(($1("foo"))); + ], + [ + m4_warn([syntax], [Unsupported attribute $1, the test may fail]) + int foo( void ) __attribute__(($1)); + ] + )], []) + ], + dnl GCC doesn't exit with an error if an unknown attribute is + dnl provided but only outputs a warning, so accept the attribute + dnl only if no warning were issued. + [AS_IF([test -s conftest.err], + [AS_VAR_SET([ac_var], [no])], + [AS_VAR_SET([ac_var], [yes])])], + [AS_VAR_SET([ac_var], [no])]) + ]) + + AS_IF([test yes = AS_VAR_GET([ac_var])], + [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_FUNC_ATTRIBUTE_$1), 1, + [Define to 1 if the system has the `$1' function attribute])], []) + + AS_VAR_POPDEF([ac_var]) +]) diff --git a/build-aux/m4/ax_pthread.m4 b/build-aux/m4/ax_pthread.m4 new file mode 100644 index 00000000..d218d1af --- /dev/null +++ b/build-aux/m4/ax_pthread.m4 @@ -0,0 +1,485 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_pthread.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# This macro figures out how to build C programs using POSIX threads. It +# sets the PTHREAD_LIBS output variable to the threads library and linker +# flags, and the PTHREAD_CFLAGS output variable to any special C compiler +# flags that are needed. (The user can also force certain compiler +# flags/libs to be tested by setting these environment variables.) +# +# Also sets PTHREAD_CC to any special C compiler that is needed for +# multi-threaded programs (defaults to the value of CC otherwise). (This +# is necessary on AIX to use the special cc_r compiler alias.) +# +# NOTE: You are assumed to not only compile your program with these flags, +# but also to link with them as well. For example, you might link with +# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS +# +# If you are only building threaded programs, you may wish to use these +# variables in your default LIBS, CFLAGS, and CC: +# +# LIBS="$PTHREAD_LIBS $LIBS" +# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +# CC="$PTHREAD_CC" +# +# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant +# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to +# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# +# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the +# PTHREAD_PRIO_INHERIT symbol is defined when compiling with +# PTHREAD_CFLAGS. +# +# ACTION-IF-FOUND is a list of shell commands to run if a threads library +# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it +# is not found. If ACTION-IF-FOUND is not specified, the default action +# will define HAVE_PTHREAD. +# +# Please let the authors know if this macro fails on any platform, or if +# you have any other suggestions or comments. This macro was based on work +# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help +# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by +# Alejandro Forero Cuervo to the autoconf macro repository. We are also +# grateful for the helpful feedback of numerous users. +# +# Updated for Autoconf 2.68 by Daniel Richard G. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2011 Daniel Richard G. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 22 + +AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) +AC_DEFUN([AX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_SED]) +AC_LANG_PUSH([C]) +ax_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on Tru64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], + [ +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + ], + [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) + ;; + + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; +esac + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +AS_IF([test "x$GCC" = "xyes"], + [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix* | freebsd*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" + ;; +esac +AS_IF([test "x$ax_pthread_check_macro" = "x--"], + [ax_pthread_check_cond=0], + [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) + +# Are we compiling with Clang? + +AC_CACHE_CHECK([whether $CC is Clang], + [ax_cv_PTHREAD_CLANG], + [ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], + [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + ], + [ax_cv_PTHREAD_CLANG=yes]) + fi + ]) +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + +ax_pthread_clang_warning=no + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= + + ax_pthread_ok=yes + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [ac_link="$ax_pthread_2step_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [break]) + ]) + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + ]) + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -mt,pthread) + AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; + + pthread-config) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) + AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac + + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + AC_MSG_RESULT([$ax_pthread_ok]) + AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_CACHE_CHECK([for joinable pthread attribute], + [ax_cv_PTHREAD_JOINABLE_ATTR], + [ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $ax_pthread_attr; return attr /* ; */])], + [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], + []) + done + ]) + AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"], + [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], + [$ax_cv_PTHREAD_JOINABLE_ATTR], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + ax_pthread_joinable_attr_defined=yes + ]) + + AC_CACHE_CHECK([whether more special flags are required for pthreads], + [ax_cv_PTHREAD_SPECIAL_FLAGS], + [ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + ]) + AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"], + [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes]) + + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + [ax_cv_PTHREAD_PRIO_INHERIT], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) + ax_pthread_prio_inherit_defined=yes + ]) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + AS_CASE(["x/$CC"], + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], + [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) + ;; + esac + fi +fi + +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + +AC_SUBST([PTHREAD_LIBS]) +AC_SUBST([PTHREAD_CFLAGS]) +AC_SUBST([PTHREAD_CC]) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "x$ax_pthread_ok" = "xyes"; then + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) + : +else + ax_pthread_ok=no + $2 +fi +AC_LANG_POP +])dnl AX_PTHREAD diff --git a/build-aux/m4/bitcoin_find_bdb48.m4 b/build-aux/m4/bitcoin_find_bdb48.m4 new file mode 100644 index 00000000..2aa493a6 --- /dev/null +++ b/build-aux/m4/bitcoin_find_bdb48.m4 @@ -0,0 +1,66 @@ +AC_DEFUN([BITCOIN_FIND_BDB48],[ + AC_MSG_CHECKING([for Berkeley DB C++ headers]) + BDB_CPPFLAGS= + BDB_LIBS= + bdbpath=X + bdb48path=X + bdbdirlist= + for _vn in 4.8 48 4 5 ''; do + for _pfx in b lib ''; do + bdbdirlist="$bdbdirlist ${_pfx}db${_vn}" + done + done + for searchpath in $bdbdirlist ''; do + test -n "${searchpath}" && searchpath="${searchpath}/" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include <${searchpath}db_cxx.h> + ]],[[ + #if !((DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || DB_VERSION_MAJOR > 4) + #error "failed to find bdb 4.8+" + #endif + ]])],[ + if test "x$bdbpath" = "xX"; then + bdbpath="${searchpath}" + fi + ],[ + continue + ]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include <${searchpath}db_cxx.h> + ]],[[ + #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 8) + #error "failed to find bdb 4.8" + #endif + ]])],[ + bdb48path="${searchpath}" + break + ],[]) + done + if test "x$bdbpath" = "xX"; then + AC_MSG_RESULT([no]) + AC_MSG_ERROR([libdb_cxx headers missing, ]AC_PACKAGE_NAME[ requires this library for wallet functionality (--disable-wallet to disable wallet functionality)]) + elif test "x$bdb48path" = "xX"; then + BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdbpath}],db_cxx) + AC_ARG_WITH([incompatible-bdb],[AS_HELP_STRING([--with-incompatible-bdb], [allow using a bdb version other than 4.8])],[ + AC_MSG_WARN([Found Berkeley DB other than 4.8; wallets opened by this build will not be portable!]) + ],[ + AC_MSG_ERROR([Found Berkeley DB other than 4.8, required for portable wallets (--with-incompatible-bdb to ignore or --disable-wallet to disable wallet functionality)]) + ]) + else + BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdb48path}],db_cxx) + bdbpath="${bdb48path}" + fi + AC_SUBST(BDB_CPPFLAGS) + + # TODO: Ideally this could find the library version and make sure it matches the headers being used + for searchlib in db_cxx-4.8 db_cxx; do + AC_CHECK_LIB([$searchlib],[main],[ + BDB_LIBS="-l${searchlib}" + break + ]) + done + if test "x$BDB_LIBS" = "x"; then + AC_MSG_ERROR([libdb_cxx missing, ]AC_PACKAGE_NAME[ requires this library for wallet functionality (--disable-wallet to disable wallet functionality)]) + fi + AC_SUBST(BDB_LIBS) +]) diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 new file mode 100644 index 00000000..5c92a020 --- /dev/null +++ b/build-aux/m4/bitcoin_qt.m4 @@ -0,0 +1,508 @@ +dnl Helper for cases where a qt dependency is not met. +dnl Output: If qt version is auto, set bitcoin_enable_qt to false. Else, exit. +AC_DEFUN([BITCOIN_QT_FAIL],[ + if test "x$bitcoin_qt_want_version" = "xauto" && test x$bitcoin_qt_force != xyes; then + if test x$bitcoin_enable_qt != xno; then + AC_MSG_WARN([$1; bitcoin-qt frontend will not be built]) + fi + bitcoin_enable_qt=no + bitcoin_enable_qt_test=no + else + AC_MSG_ERROR([$1]) + fi +]) + +AC_DEFUN([BITCOIN_QT_CHECK],[ + if test "x$bitcoin_enable_qt" != "xno" && test x$bitcoin_qt_want_version != xno; then + true + $1 + else + true + $2 + fi +]) + +dnl BITCOIN_QT_PATH_PROGS([FOO], [foo foo2], [/path/to/search/first], [continue if missing]) +dnl Helper for finding the path of programs needed for Qt. +dnl Inputs: $1: Variable to be set +dnl Inputs: $2: List of programs to search for +dnl Inputs: $3: Look for $2 here before $PATH +dnl Inputs: $4: If "yes", don't fail if $2 is not found. +dnl Output: $1 is set to the path of $2 if found. $2 are searched in order. +AC_DEFUN([BITCOIN_QT_PATH_PROGS],[ + BITCOIN_QT_CHECK([ + if test "x$3" != "x"; then + AC_PATH_PROGS($1,$2,,$3) + else + AC_PATH_PROGS($1,$2) + fi + if test "x$$1" = "x" && test "x$4" != "xyes"; then + BITCOIN_QT_FAIL([$1 not found]) + fi + ]) +]) + +dnl Initialize qt input. +dnl This must be called before any other BITCOIN_QT* macros to ensure that +dnl input variables are set correctly. +dnl CAUTION: Do not use this inside of a conditional. +AC_DEFUN([BITCOIN_QT_INIT],[ + dnl enable qt support + AC_ARG_WITH([gui], + [AS_HELP_STRING([--with-gui@<:@=no|qt4|qt5|auto@:>@], + [build bitcoin-qt GUI (default=auto, qt5 tried first)])], + [ + bitcoin_qt_want_version=$withval + if test x$bitcoin_qt_want_version = xyes; then + bitcoin_qt_force=yes + bitcoin_qt_want_version=auto + fi + ], + [bitcoin_qt_want_version=auto]) + + AC_ARG_WITH([qt-incdir],[AS_HELP_STRING([--with-qt-incdir=INC_DIR],[specify qt include path (overridden by pkgconfig)])], [qt_include_path=$withval], []) + AC_ARG_WITH([qt-libdir],[AS_HELP_STRING([--with-qt-libdir=LIB_DIR],[specify qt lib path (overridden by pkgconfig)])], [qt_lib_path=$withval], []) + AC_ARG_WITH([qt-plugindir],[AS_HELP_STRING([--with-qt-plugindir=PLUGIN_DIR],[specify qt plugin path (overridden by pkgconfig)])], [qt_plugin_path=$withval], []) + AC_ARG_WITH([qt-translationdir],[AS_HELP_STRING([--with-qt-translationdir=PLUGIN_DIR],[specify qt translation path (overridden by pkgconfig)])], [qt_translation_path=$withval], []) + AC_ARG_WITH([qt-bindir],[AS_HELP_STRING([--with-qt-bindir=BIN_DIR],[specify qt bin path])], [qt_bin_path=$withval], []) + + AC_ARG_WITH([qtdbus], + [AS_HELP_STRING([--with-qtdbus], + [enable DBus support (default is yes if qt is enabled and QtDBus is found)])], + [use_dbus=$withval], + [use_dbus=auto]) + + AC_SUBST(QT_TRANSLATION_DIR,$qt_translation_path) +]) + +dnl Find the appropriate version of Qt libraries and includes. +dnl Inputs: $1: Whether or not pkg-config should be used. yes|no. Default: yes. +dnl Inputs: $2: If $1 is "yes" and --with-gui=auto, which qt version should be +dnl tried first. +dnl Outputs: See _BITCOIN_QT_FIND_LIBS_* +dnl Outputs: Sets variables for all qt-related tools. +dnl Outputs: bitcoin_enable_qt, bitcoin_enable_qt_dbus, bitcoin_enable_qt_test +AC_DEFUN([BITCOIN_QT_CONFIGURE],[ + use_pkgconfig=$1 + + if test x$use_pkgconfig = x; then + use_pkgconfig=yes + fi + + if test x$use_pkgconfig = xyes; then + BITCOIN_QT_CHECK([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG([$2])]) + else + BITCOIN_QT_CHECK([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG]) + fi + + dnl This is ugly and complicated. Yuck. Works as follows: + dnl We can't discern whether Qt4 builds are static or not. For Qt5, we can + dnl check a header to find out. When Qt is built statically, some plugins must + dnl be linked into the final binary as well. These plugins have changed between + dnl Qt4 and Qt5. With Qt5, languages moved into core and the WindowsIntegration + dnl plugin was added. Since we can't tell if Qt4 is static or not, it is + dnl assumed for windows builds. + dnl _BITCOIN_QT_CHECK_STATIC_PLUGINS does a quick link-check and appends the + dnl results to QT_LIBS. + BITCOIN_QT_CHECK([ + TEMP_CPPFLAGS=$CPPFLAGS + TEMP_CXXFLAGS=$CXXFLAGS + CPPFLAGS="$QT_INCLUDES $CPPFLAGS" + CXXFLAGS="$PIC_FLAGS $CXXFLAGS" + if test x$bitcoin_qt_got_major_vers = x5; then + _BITCOIN_QT_IS_STATIC + if test x$bitcoin_cv_static_qt = xyes; then + _BITCOIN_QT_FIND_STATIC_PLUGINS + AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) + + if test x$qt_plugin_path != x; then + QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" + fi + if test x$use_pkgconfig = xyes; then + PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"]) + fi + AC_CACHE_CHECK(for Qt < 5.4, bitcoin_cv_need_acc_widget,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [[#include ]],[[ + #if QT_VERSION >= 0x050400 + choke; + #endif + ]])], + [bitcoin_cv_need_acc_widget=yes], + [bitcoin_cv_need_acc_widget=no]) + ]) + if test "x$bitcoin_cv_need_acc_widget" = "xyes"; then + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets]) + fi + if test x$TARGET_OS = xwindows; then + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows]) + AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows]) + elif test x$TARGET_OS = xlinux; then + + PKG_CHECK_MODULES([X11XCB], [x11-xcb], [QT_LIBS="$X11XCB_LIBS $QT_LIBS"]) + if ${PKG_CONFIG} --exists "Qt5Core >= 5.5" 2>/dev/null; then + PKG_CHECK_MODULES([QTXCBQPA], [Qt5XcbQpa], [QT_LIBS="$QTXCBQPA_LIBS $QT_LIBS"]) + fi + + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)],[-lqxcb -lxcb-static]) + AC_DEFINE(QT_QPA_PLATFORM_XCB, 1, [Define this symbol if the qt platform is xcb]) + elif test x$TARGET_OS = xdarwin; then + AX_CHECK_LINK_FLAG([[-framework IOKit]],[QT_LIBS="$QT_LIBS -framework IOKit"],[AC_MSG_ERROR(could not iokit framework)]) + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)],[-lqcocoa]) + AC_DEFINE(QT_QPA_PLATFORM_COCOA, 1, [Define this symbol if the qt platform is cocoa]) + fi + fi + else + if test x$TARGET_OS = xwindows; then + AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) + _BITCOIN_QT_CHECK_STATIC_PLUGINS([ + Q_IMPORT_PLUGIN(qcncodecs) + Q_IMPORT_PLUGIN(qjpcodecs) + Q_IMPORT_PLUGIN(qtwcodecs) + Q_IMPORT_PLUGIN(qkrcodecs) + Q_IMPORT_PLUGIN(AccessibleFactory)], + [-lqcncodecs -lqjpcodecs -lqtwcodecs -lqkrcodecs -lqtaccessiblewidgets]) + fi + fi + CPPFLAGS=$TEMP_CPPFLAGS + CXXFLAGS=$TEMP_CXXFLAGS + ]) + + if test x$use_pkgconfig$qt_bin_path = xyes; then + if test x$bitcoin_qt_got_major_vers = x5; then + qt_bin_path="`$PKG_CONFIG --variable=host_bins Qt5Core 2>/dev/null`" + fi + fi + + if test x$use_hardening != xno; then + BITCOIN_QT_CHECK([ + AC_MSG_CHECKING(whether -fPIE can be used with this Qt config) + TEMP_CPPFLAGS=$CPPFLAGS + TEMP_CXXFLAGS=$CXXFLAGS + CPPFLAGS="$QT_INCLUDES $CPPFLAGS" + CXXFLAGS="$PIE_FLAGS $CXXFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ + #if defined(QT_REDUCE_RELOCATIONS) + choke; + #endif + ]])], + [ AC_MSG_RESULT(yes); QT_PIE_FLAGS=$PIE_FLAGS ], + [ AC_MSG_RESULT(no); QT_PIE_FLAGS=$PIC_FLAGS] + ) + CPPFLAGS=$TEMP_CPPFLAGS + CXXFLAGS=$TEMP_CXXFLAGS + ]) + else + BITCOIN_QT_CHECK([ + AC_MSG_CHECKING(whether -fPIC is needed with this Qt config) + TEMP_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$QT_INCLUDES $CPPFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ + #if defined(QT_REDUCE_RELOCATIONS) + choke; + #endif + ]])], + [ AC_MSG_RESULT(no)], + [ AC_MSG_RESULT(yes); QT_PIE_FLAGS=$PIC_FLAGS] + ) + CPPFLAGS=$TEMP_CPPFLAGS + ]) + fi + + BITCOIN_QT_PATH_PROGS([MOC], [moc-qt${bitcoin_qt_got_major_vers} moc${bitcoin_qt_got_major_vers} moc], $qt_bin_path) + BITCOIN_QT_PATH_PROGS([UIC], [uic-qt${bitcoin_qt_got_major_vers} uic${bitcoin_qt_got_major_vers} uic], $qt_bin_path) + BITCOIN_QT_PATH_PROGS([RCC], [rcc-qt${bitcoin_qt_got_major_vers} rcc${bitcoin_qt_got_major_vers} rcc], $qt_bin_path) + BITCOIN_QT_PATH_PROGS([LRELEASE], [lrelease-qt${bitcoin_qt_got_major_vers} lrelease${bitcoin_qt_got_major_vers} lrelease], $qt_bin_path) + BITCOIN_QT_PATH_PROGS([LUPDATE], [lupdate-qt${bitcoin_qt_got_major_vers} lupdate${bitcoin_qt_got_major_vers} lupdate],$qt_bin_path, yes) + + MOC_DEFS='-DHAVE_CONFIG_H -I$(srcdir)' + case $host in + *darwin*) + BITCOIN_QT_CHECK([ + MOC_DEFS="${MOC_DEFS} -DQ_OS_MAC" + base_frameworks="-framework Foundation -framework ApplicationServices -framework AppKit" + AX_CHECK_LINK_FLAG([[$base_frameworks]],[QT_LIBS="$QT_LIBS $base_frameworks"],[AC_MSG_ERROR(could not find base frameworks)]) + ]) + ;; + *mingw*) + BITCOIN_QT_CHECK([ + AX_CHECK_LINK_FLAG([[-mwindows]],[QT_LDFLAGS="$QT_LDFLAGS -mwindows"],[AC_MSG_WARN(-mwindows linker support not detected)]) + ]) + esac + + + dnl enable qt support + AC_MSG_CHECKING(whether to build ]AC_PACKAGE_NAME[ GUI) + BITCOIN_QT_CHECK([ + bitcoin_enable_qt=yes + bitcoin_enable_qt_test=yes + if test x$have_qt_test = xno; then + bitcoin_enable_qt_test=no + fi + bitcoin_enable_qt_dbus=no + if test x$use_dbus != xno && test x$have_qt_dbus = xyes; then + bitcoin_enable_qt_dbus=yes + fi + if test x$use_dbus = xyes && test x$have_qt_dbus = xno; then + AC_MSG_ERROR("libQtDBus not found. Install libQtDBus or remove --with-qtdbus.") + fi + if test x$LUPDATE = x; then + AC_MSG_WARN("lupdate is required to update qt translations") + fi + ],[ + bitcoin_enable_qt=no + ]) + AC_MSG_RESULT([$bitcoin_enable_qt (Qt${bitcoin_qt_got_major_vers})]) + + AC_SUBST(QT_PIE_FLAGS) + AC_SUBST(QT_INCLUDES) + AC_SUBST(QT_LIBS) + AC_SUBST(QT_LDFLAGS) + AC_SUBST(QT_DBUS_INCLUDES) + AC_SUBST(QT_DBUS_LIBS) + AC_SUBST(QT_TEST_INCLUDES) + AC_SUBST(QT_TEST_LIBS) + AC_SUBST(QT_SELECT, qt${bitcoin_qt_got_major_vers}) + AC_SUBST(MOC_DEFS) +]) + +dnl All macros below are internal and should _not_ be used from the main +dnl configure.ac. +dnl ---- + +dnl Internal. Check if the included version of Qt is Qt5. +dnl Requires: INCLUDES must be populated as necessary. +dnl Output: bitcoin_cv_qt5=yes|no +AC_DEFUN([_BITCOIN_QT_CHECK_QT5],[ + AC_CACHE_CHECK(for Qt 5, bitcoin_cv_qt5,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [[#include ]], + [[ + #if QT_VERSION < 0x050000 + choke me + #else + return 0; + #endif + ]])], + [bitcoin_cv_qt5=yes], + [bitcoin_cv_qt5=no]) +])]) + +dnl Internal. Check if the linked version of Qt was built as static libs. +dnl Requires: Qt5. This check cannot determine if Qt4 is static. +dnl Requires: INCLUDES and LIBS must be populated as necessary. +dnl Output: bitcoin_cv_static_qt=yes|no +dnl Output: Defines QT_STATICPLUGIN if plugins are static. +AC_DEFUN([_BITCOIN_QT_IS_STATIC],[ + AC_CACHE_CHECK(for static Qt, bitcoin_cv_static_qt,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [[#include ]], + [[ + #if defined(QT_STATIC) + return 0; + #else + choke me + #endif + ]])], + [bitcoin_cv_static_qt=yes], + [bitcoin_cv_static_qt=no]) + ]) + if test xbitcoin_cv_static_qt = xyes; then + AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol for static Qt plugins]) + fi +]) + +dnl Internal. Check if the link-requirements for static plugins are met. +dnl Requires: INCLUDES and LIBS must be populated as necessary. +dnl Inputs: $1: A series of Q_IMPORT_PLUGIN(). +dnl Inputs: $2: The libraries that resolve $1. +dnl Output: QT_LIBS is prepended or configure exits. +AC_DEFUN([_BITCOIN_QT_CHECK_STATIC_PLUGINS],[ + AC_MSG_CHECKING(for static Qt plugins: $2) + CHECK_STATIC_PLUGINS_TEMP_LIBS="$LIBS" + LIBS="$2 $QT_LIBS $LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #define QT_STATICPLUGIN + #include + $1]], + [[return 0;]])], + [AC_MSG_RESULT(yes); QT_LIBS="$2 $QT_LIBS"], + [AC_MSG_RESULT(no); BITCOIN_QT_FAIL(Could not resolve: $2)]) + LIBS="$CHECK_STATIC_PLUGINS_TEMP_LIBS" +]) + +dnl Internal. Find paths necessary for linking qt static plugins +dnl Inputs: bitcoin_qt_got_major_vers. 4 or 5. +dnl Inputs: qt_plugin_path. optional. +dnl Outputs: QT_LIBS is appended +AC_DEFUN([_BITCOIN_QT_FIND_STATIC_PLUGINS],[ + if test x$bitcoin_qt_got_major_vers = x5; then + if test x$qt_plugin_path != x; then + QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" + if test -d "$qt_plugin_path/accessible"; then + QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" + fi + fi + m4_ifdef([PKG_CHECK_MODULES],[ + if test x$use_pkgconfig = xyes; then + PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"]) + if test x$TARGET_OS = xlinux; then + PKG_CHECK_MODULES([X11XCB], [x11-xcb], [QT_LIBS="$X11XCB_LIBS $QT_LIBS"]) + if ${PKG_CONFIG} --exists "Qt5Core >= 5.5" 2>/dev/null; then + PKG_CHECK_MODULES([QTXCBQPA], [Qt5XcbQpa], [QT_LIBS="$QTXCBQPA_LIBS $QT_LIBS"]) + fi + elif test x$TARGET_OS = xdarwin; then + PKG_CHECK_MODULES([QTPRINT], [Qt5PrintSupport], [QT_LIBS="$QTPRINT_LIBS $QT_LIBS"]) + fi + else + if ${PKG_CONFIG} --exists "Qt5Core >= 5.6" 2>/dev/null; then + QT_LIBS="-lQt5PlatformSupport $QT_LIBS" + fi + fi + ]) + else + if test x$qt_plugin_path != x; then + QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" + QT_LIBS="$QT_LIBS -L$qt_plugin_path/codecs" + fi + fi +]) + +dnl Internal. Find Qt libraries using pkg-config. +dnl Inputs: bitcoin_qt_want_version (from --with-gui=). The version to check +dnl first. +dnl Inputs: $1: If bitcoin_qt_want_version is "auto", check for this version +dnl first. +dnl Outputs: All necessary QT_* variables are set. +dnl Outputs: bitcoin_qt_got_major_vers is set to "4" or "5". +dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no. +AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG],[ + m4_ifdef([PKG_CHECK_MODULES],[ + auto_priority_version=$1 + if test x$auto_priority_version = x; then + auto_priority_version=qt5 + fi + if test x$bitcoin_qt_want_version = xqt5 || ( test x$bitcoin_qt_want_version = xauto && test x$auto_priority_version = xqt5 ); then + QT_LIB_PREFIX=Qt5 + bitcoin_qt_got_major_vers=5 + else + QT_LIB_PREFIX=Qt + bitcoin_qt_got_major_vers=4 + fi + qt5_modules="Qt5Core Qt5Gui Qt5Network Qt5Widgets" + qt4_modules="QtCore QtGui QtNetwork" + BITCOIN_QT_CHECK([ + if test x$bitcoin_qt_want_version = xqt5 || ( test x$bitcoin_qt_want_version = xauto && test x$auto_priority_version = xqt5 ); then + PKG_CHECK_MODULES([QT], [$qt5_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes],[have_qt=no]) + elif test x$bitcoin_qt_want_version = xqt4 || ( test x$bitcoin_qt_want_version = xauto && test x$auto_priority_version = xqt4 ); then + PKG_CHECK_MODULES([QT], [$qt4_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes], [have_qt=no]) + fi + + 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 = 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]) + fi + fi + if test x$have_qt != xyes; then + have_qt=no + BITCOIN_QT_FAIL([Qt dependencies not found]) + fi + ]) + BITCOIN_QT_CHECK([ + PKG_CHECK_MODULES([QT_TEST], [${QT_LIB_PREFIX}Test], [QT_TEST_INCLUDES="$QT_TEST_CFLAGS"; have_qt_test=yes], [have_qt_test=no]) + if test x$use_dbus != xno; then + PKG_CHECK_MODULES([QT_DBUS], [${QT_LIB_PREFIX}DBus], [QT_DBUS_INCLUDES="$QT_DBUS_CFLAGS"; have_qt_dbus=yes], [have_qt_dbus=no]) + fi + ]) + ]) + true; dnl +]) + +dnl Internal. Find Qt libraries without using pkg-config. Version is deduced +dnl from the discovered headers. +dnl Inputs: bitcoin_qt_want_version (from --with-gui=). The version to use. +dnl If "auto", the version will be discovered by _BITCOIN_QT_CHECK_QT5. +dnl Outputs: All necessary QT_* variables are set. +dnl Outputs: bitcoin_qt_got_major_vers is set to "4" or "5". +dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no. +AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ + TEMP_CPPFLAGS="$CPPFLAGS" + TEMP_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$PIC_FLAGS $CXXFLAGS" + TEMP_LIBS="$LIBS" + BITCOIN_QT_CHECK([ + if test x$qt_include_path != x; then + QT_INCLUDES="-I$qt_include_path -I$qt_include_path/QtCore -I$qt_include_path/QtGui -I$qt_include_path/QtWidgets -I$qt_include_path/QtNetwork -I$qt_include_path/QtTest -I$qt_include_path/QtDBus" + CPPFLAGS="$QT_INCLUDES $CPPFLAGS" + fi + ]) + + BITCOIN_QT_CHECK([AC_CHECK_HEADER([QtPlugin],,BITCOIN_QT_FAIL(QtCore headers missing))]) + BITCOIN_QT_CHECK([AC_CHECK_HEADER([QApplication],, BITCOIN_QT_FAIL(QtGui headers missing))]) + BITCOIN_QT_CHECK([AC_CHECK_HEADER([QLocalSocket],, BITCOIN_QT_FAIL(QtNetwork headers missing))]) + + BITCOIN_QT_CHECK([ + if test x$bitcoin_qt_want_version = xauto; then + _BITCOIN_QT_CHECK_QT5 + fi + if test x$bitcoin_cv_qt5 = xyes || test x$bitcoin_qt_want_version = xqt5; then + QT_LIB_PREFIX=Qt5 + bitcoin_qt_got_major_vers=5 + else + QT_LIB_PREFIX=Qt + bitcoin_qt_got_major_vers=4 + fi + ]) + + BITCOIN_QT_CHECK([ + LIBS= + if test x$qt_lib_path != x; then + LIBS="$LIBS -L$qt_lib_path" + fi + + if test x$TARGET_OS = xwindows; then + AC_CHECK_LIB([imm32], [main],, BITCOIN_QT_FAIL(libimm32 not found)) + fi + ]) + + BITCOIN_QT_CHECK(AC_CHECK_LIB([z] ,[main],,AC_MSG_WARN([zlib not found. Assuming qt has it built-in]))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([png] ,[main],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in]))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([jpeg] ,[main],,AC_MSG_WARN([libjpeg not found. Assuming qt has it built-in]))) + BITCOIN_QT_CHECK(AC_SEARCH_LIBS([pcre16_exec], [qtpcre pcre16],,AC_MSG_WARN([libpcre16 not found. Assuming qt has it built-in]))) + BITCOIN_QT_CHECK(AC_SEARCH_LIBS([hb_ot_tags_from_script] ,[qtharfbuzzng harfbuzz],,AC_MSG_WARN([libharfbuzz not found. Assuming qt has it built-in or support is disabled]))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Core] ,[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXCore not found))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Gui] ,[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXGui not found))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Network],[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXNetwork not found))) + if test x$bitcoin_qt_got_major_vers = x5; then + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Widgets],[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXWidgets not found))) + fi + QT_LIBS="$LIBS" + LIBS="$TEMP_LIBS" + + BITCOIN_QT_CHECK([ + LIBS= + if test x$qt_lib_path != x; then + LIBS="-L$qt_lib_path" + fi + AC_CHECK_LIB([${QT_LIB_PREFIX}Test], [main],, have_qt_test=no) + AC_CHECK_HEADER([QTest],, have_qt_test=no) + QT_TEST_LIBS="$LIBS" + if test x$use_dbus != xno; then + LIBS= + if test x$qt_lib_path != x; then + LIBS="-L$qt_lib_path" + fi + AC_CHECK_LIB([${QT_LIB_PREFIX}DBus], [main],, have_qt_dbus=no) + AC_CHECK_HEADER([QtDBus],, have_qt_dbus=no) + QT_DBUS_LIBS="$LIBS" + fi + ]) + CPPFLAGS="$TEMP_CPPFLAGS" + CXXFLAGS="$TEMP_CXXFLAGS" + LIBS="$TEMP_LIBS" +]) + diff --git a/build-aux/m4/bitcoin_subdir_to_include.m4 b/build-aux/m4/bitcoin_subdir_to_include.m4 new file mode 100644 index 00000000..66f106c7 --- /dev/null +++ b/build-aux/m4/bitcoin_subdir_to_include.m4 @@ -0,0 +1,14 @@ +dnl BITCOIN_SUBDIR_TO_INCLUDE([CPPFLAGS-VARIABLE-NAME],[SUBDIRECTORY-NAME],[HEADER-FILE]) +dnl SUBDIRECTORY-NAME must end with a path separator +AC_DEFUN([BITCOIN_SUBDIR_TO_INCLUDE],[ + if test "x$2" = "x"; then + AC_MSG_RESULT([default]) + else + echo "#include <$2$3.h>" >conftest.cpp + newinclpath=`${CXXCPP} ${CPPFLAGS} -M conftest.cpp 2>/dev/null | [ tr -d '\\n\\r\\\\' | sed -e 's/^.*[[:space:]:]\(\/[^[:space:]]*\)]$3[\.h[[:space:]].*$/\1/' -e t -e d`] + AC_MSG_RESULT([${newinclpath}]) + if test "x${newinclpath}" != "x"; then + eval "$1=\"\$$1\"' -I${newinclpath}'" + fi + fi +]) diff --git a/build-aux/m4/l_atomic.m4 b/build-aux/m4/l_atomic.m4 new file mode 100644 index 00000000..906724b6 --- /dev/null +++ b/build-aux/m4/l_atomic.m4 @@ -0,0 +1,40 @@ +# Some versions of gcc/libstdc++ require linking with -latomic if +# using the C++ atomic library. +# +# Sourced from http://bugs.debian.org/797228 + +m4_define([_CHECK_ATOMIC_testbody], [[ + #include + #include + + int main() { + std::atomic a{}; + + int64_t v = 5; + int64_t r = a.fetch_add(v); + return static_cast(r); + } +]]) + +AC_DEFUN([CHECK_ATOMIC], [ + + AC_LANG_PUSH(C++) + + AC_MSG_CHECKING([whether std::atomic can be used without link library]) + + AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_ATOMIC_testbody])],[ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_RESULT([no]) + LIBS="$LIBS -latomic" + AC_MSG_CHECKING([whether std::atomic needs -latomic]) + AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_ATOMIC_testbody])],[ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_FAILURE([cannot figure our how to use std::atomic]) + ]) + ]) + + AC_LANG_POP +]) diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..656a1af1 --- /dev/null +++ b/configure.ac @@ -0,0 +1,958 @@ +dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) +AC_PREREQ([2.60]) +define(_CLIENT_VERSION_MAJOR, 0) +define(_CLIENT_VERSION_MINOR, 12) +define(_CLIENT_VERSION_REVISION, 1) +define(_CLIENT_VERSION_BUILD, 0) +define(_CLIENT_VERSION_IS_RELEASE, true) +define(_COPYRIGHT_YEAR, 2016) +AC_INIT([Bitcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/bitcoin/bitcoin/issues],[bitcoin]) +AC_CONFIG_SRCDIR([src/main.cpp]) +AC_CONFIG_HEADERS([src/config/bitcoin-config.h]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([build-aux/m4]) + +AC_CANONICAL_HOST + +AH_TOP([#ifndef BITCOIN_CONFIG_H]) +AH_TOP([#define BITCOIN_CONFIG_H]) +AH_BOTTOM([#endif //BITCOIN_CONFIG_H]) + +dnl faketime breaks configure and is only needed for make. Disable it here. +unset FAKETIME + +dnl Automake init set-up and checks +AM_INIT_AUTOMAKE([no-define subdir-objects foreign]) + +dnl faketime messes with timestamps and causes configure to be re-run. +dnl --disable-maintainer-mode can be used to bypass this. +AM_MAINTAINER_MODE([enable]) + +dnl make the compilation flags quiet unless V=1 is used +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +dnl Compiler checks (here before libtool). +if test "x${CXXFLAGS+set}" = "xset"; then + CXXFLAGS_overridden=yes +else + CXXFLAGS_overridden=no +fi +AC_PROG_CXX +m4_ifdef([AC_PROG_OBJCXX],[AC_PROG_OBJCXX]) + +dnl By default, libtool for mingw refuses to link static libs into a dll for +dnl fear of mixing pic/non-pic objects, and import/export complications. Since +dnl we have those under control, re-enable that functionality. +case $host in + *mingw*) + lt_cv_deplibs_check_method="pass_all" + ;; +esac +dnl Require C++11 compiler (no GNU extensions) +AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory], [nodefault]) +dnl Check if -latomic is required for +CHECK_ATOMIC + +dnl Unless the user specified OBJCXX, force it to be the same as CXX. This ensures +dnl that we get the same -std flags for both. +m4_ifdef([AC_PROG_OBJCXX],[ +if test "x${OBJCXX+set}" = "x"; then + OBJCXX="${CXX}" +fi +AC_PROG_OBJCXX +]) + +dnl Libtool init checks. +LT_INIT([pic-only]) + +dnl Check/return PATH for base programs. +AC_PATH_TOOL(AR, ar) +AC_PATH_TOOL(RANLIB, ranlib) +AC_PATH_TOOL(STRIP, strip) +AC_PATH_TOOL(GCOV, gcov) +AC_PATH_PROG(LCOV, lcov) +AC_PATH_PROG(JAVA, java) +AC_PATH_PROG(PYTHON, python) +AC_PATH_PROG(GENHTML, genhtml) +AC_PATH_PROG([GIT], [git]) +AC_PATH_PROG(CCACHE,ccache) +AC_PATH_PROG(XGETTEXT,xgettext) +AC_PATH_PROG(HEXDUMP,hexdump) +AC_PATH_TOOL(READELF, readelf) +AC_PATH_TOOL(CPPFILT, c++filt) + +dnl pkg-config check. +PKG_PROG_PKG_CONFIG + +# Enable wallet +AC_ARG_ENABLE([wallet], + [AS_HELP_STRING([--disable-wallet], + [disable wallet (enabled by default)])], + [enable_wallet=$enableval], + [enable_wallet=yes]) + +AC_ARG_WITH([miniupnpc], + [AS_HELP_STRING([--with-miniupnpc], + [enable UPNP (default is yes if libminiupnpc is found)])], + [use_upnp=$withval], + [use_upnp=auto]) + +AC_ARG_ENABLE([upnp-default], + [AS_HELP_STRING([--enable-upnp-default], + [if UPNP is enabled, turn it on at startup (default is no)])], + [use_upnp_default=$enableval], + [use_upnp_default=no]) + +AC_ARG_ENABLE(tests, + AS_HELP_STRING([--disable-tests],[do not compile tests (default is to compile)]), + [use_tests=$enableval], + [use_tests=yes]) + +AC_ARG_ENABLE(gui-tests, + AS_HELP_STRING([--disable-gui-tests],[do not compile GUI tests (default is to compile if GUI and tests enabled)]), + [use_gui_tests=$enableval], + [use_gui_tests=$use_tests]) + +AC_ARG_ENABLE(bench, + AS_HELP_STRING([--disable-bench],[do not compile benchmarks (default is to compile)]), + [use_bench=$enableval], + [use_bench=yes]) + +AC_ARG_WITH([comparison-tool], + AS_HELP_STRING([--with-comparison-tool],[path to java comparison tool (requires --enable-tests)]), + [use_comparison_tool=$withval], + [use_comparison_tool=no]) + +AC_ARG_ENABLE([comparison-tool-reorg-tests], + AS_HELP_STRING([--enable-comparison-tool-reorg-tests],[enable expensive reorg tests in the comparison tool (default no)]), + [use_comparison_tool_reorg_tests=$enableval], + [use_comparison_tool_reorg_tests=no]) + +AC_ARG_ENABLE([extended-rpc-tests], + AS_HELP_STRING([--enable-extended-rpc-tests],[enable expensive RPC tests when using lcov (default no)]), + [use_extended_rpc_tests=$enableval], + [use_extended_rpc_tests=no]) + +AC_ARG_ENABLE([hardening], + [AS_HELP_STRING([--disable-hardening], + [do not attempt to harden the resulting executables (default is to harden)])], + [use_hardening=$enableval], + [use_hardening=yes]) + +AC_ARG_ENABLE([reduce-exports], + [AS_HELP_STRING([--enable-reduce-exports], + [attempt to reduce exported symbols in the resulting executables (default is no)])], + [use_reduce_exports=$enableval], + [use_reduce_exports=no]) + +AC_ARG_ENABLE([ccache], + [AS_HELP_STRING([--disable-ccache], + [do not use ccache for building (default is to use if found)])], + [use_ccache=$enableval], + [use_ccache=auto]) + +AC_ARG_ENABLE([lcov], + [AS_HELP_STRING([--enable-lcov], + [enable lcov testing (default is no)])], + [use_lcov=yes], + [use_lcov=no]) + +AC_ARG_ENABLE([glibc-back-compat], + [AS_HELP_STRING([--enable-glibc-back-compat], + [enable backwards compatibility with glibc])], + [use_glibc_compat=$enableval], + [use_glibc_compat=no]) + +AC_ARG_WITH([protoc-bindir],[AS_HELP_STRING([--with-protoc-bindir=BIN_DIR],[specify protoc bin path])], [protoc_bin_path=$withval], []) + +# Enable debug +AC_ARG_ENABLE([debug], + [AS_HELP_STRING([--enable-debug], + [use debug compiler flags and macros (default is no)])], + [enable_debug=$enableval], + [enable_debug=no]) + +if test "x$enable_debug" = xyes; then + CPPFLAGS="$CPPFLAGS -DDEBUG -DDEBUG_LOCKORDER" + if test "x$GCC" = xyes; then + CFLAGS="$CFLAGS -g3 -O0" + fi + + if test "x$GXX" = xyes; then + CXXFLAGS="$CXXFLAGS -g3 -O0" + fi +fi + +## TODO: Remove these hard-coded paths and flags. They are here for the sake of +## compatibility with the legacy buildsystem. +## +if test "x$CXXFLAGS_overridden" = "xno"; then + CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter" +fi +CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" + +AC_ARG_WITH([utils], + [AS_HELP_STRING([--with-utils], + [build bitcoin-cli bitcoin-tx (default=yes)])], + [build_bitcoin_utils=$withval], + [build_bitcoin_utils=yes]) + +AC_ARG_WITH([libs], + [AS_HELP_STRING([--with-libs], + [build libraries (default=yes)])], + [build_bitcoin_libs=$withval], + [build_bitcoin_libs=yes]) + +AC_ARG_WITH([daemon], + [AS_HELP_STRING([--with-daemon], + [build bitcoind daemon (default=yes)])], + [build_bitcoind=$withval], + [build_bitcoind=yes]) + +AC_LANG_PUSH([C++]) + +use_pkgconfig=yes +case $host in + *mingw*) + + #pkgconfig does more harm than good with MinGW + use_pkgconfig=no + + TARGET_OS=windows + AC_CHECK_LIB([mingwthrd], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([kernel32], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([user32], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([gdi32], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([comdlg32], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([winspool], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([winmm], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([shell32], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([comctl32], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([ole32], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([oleaut32], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([uuid], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([rpcrt4], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([advapi32], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([ws2_32], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([mswsock], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([shlwapi], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([iphlpapi], [main],, AC_MSG_ERROR(lib missing)) + AC_CHECK_LIB([crypt32], [main],, AC_MSG_ERROR(lib missing)) + + # -static is interpreted by libtool, where it has a different meaning. + # In libtool-speak, it's -all-static. + AX_CHECK_LINK_FLAG([[-static]],[LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static"]) + + AC_PATH_PROG([MAKENSIS], [makensis], none) + if test x$MAKENSIS = xnone; then + AC_MSG_WARN("makensis not found. Cannot create installer.") + fi + + AC_PATH_TOOL(WINDRES, windres, none) + if test x$WINDRES = xnone; then + AC_MSG_ERROR("windres not found") + fi + + CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB" + LEVELDB_TARGET_FLAGS="-DOS_WINDOWS" + if test "x$CXXFLAGS_overridden" = "xno"; then + CXXFLAGS="$CXXFLAGS -w" + fi + case $host in + i?86-*) WINDOWS_BITS=32 ;; + x86_64-*) WINDOWS_BITS=64 ;; + *) AC_MSG_ERROR("Could not determine win32/win64 for installer") ;; + esac + AC_SUBST(WINDOWS_BITS) + + dnl libtool insists upon adding -nostdlib and a list of objects/libs to link against. + dnl That breaks our ability to build dll's with static libgcc/libstdc++/libssp. Override + dnl its command here, with the predeps/postdeps removed, and -static inserted. Postdeps are + dnl also overridden to prevent their insertion later. + dnl This should only affect dll's. + archive_cmds_CXX="\$CC -shared \$libobjs \$deplibs \$compiler_flags -static -o \$output_objdir/\$soname \${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker \$lib" + postdeps_CXX= + + ;; + *darwin*) + TARGET_OS=darwin + LEVELDB_TARGET_FLAGS="-DOS_MACOSX" + if test x$cross_compiling != xyes; then + BUILD_OS=darwin + AC_CHECK_PROG([PORT],port, port) + if test x$PORT = xport; then + dnl add default macports paths + CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" + LIBS="$LIBS -L/opt/local/lib" + if test -d /opt/local/include/db48; then + CPPFLAGS="$CPPFLAGS -I/opt/local/include/db48" + LIBS="$LIBS -L/opt/local/lib/db48" + fi + fi + + AC_CHECK_PROG([BREW],brew, brew) + if test x$BREW = xbrew; then + dnl These Homebrew packages may be keg-only, meaning that they won't be found + dnl in expected paths because they may conflict with system files. Ask + dnl Homebrew where each one is located, then adjust paths accordingly. + dnl It's safe to add these paths even if the functionality is disabled by + dnl the user (--without-wallet or --without-gui for example). + + openssl_prefix=`$BREW --prefix openssl 2>/dev/null` + bdb_prefix=`$BREW --prefix berkeley-db4 2>/dev/null` + qt5_prefix=`$BREW --prefix qt5 2>/dev/null` + if test x$openssl_prefix != x; then + PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH" + export PKG_CONFIG_PATH + fi + if test x$bdb_prefix != x; then + CPPFLAGS="$CPPFLAGS -I$bdb_prefix/include" + LIBS="$LIBS -L$bdb_prefix/lib" + fi + if test x$qt5_prefix != x; then + PKG_CONFIG_PATH="$qt5_prefix/lib/pkgconfig:$PKG_CONFIG_PATH" + export PKG_CONFIG_PATH + fi + fi + else + case $build_os in + *darwin*) + BUILD_OS=darwin + ;; + *) + AC_PATH_TOOL([INSTALLNAMETOOL], [install_name_tool], install_name_tool) + AC_PATH_TOOL([OTOOL], [otool], otool) + AC_PATH_PROGS([GENISOIMAGE], [genisoimage mkisofs],genisoimage) + + dnl libtool will try to strip the static lib, which is a problem for + dnl cross-builds because strip attempts to call a hard-coded ld, + dnl which may not exist in the path. Stripping the .a is not + dnl necessary, so just disable it. + old_striplib= + ;; + esac + fi + + AX_CHECK_LINK_FLAG([[-Wl,-headerpad_max_install_names]], [LDFLAGS="$LDFLAGS -Wl,-headerpad_max_install_names"]) + CPPFLAGS="$CPPFLAGS -DMAC_OSX" + OBJCXXFLAGS="$CXXFLAGS" + ;; + *linux*) + TARGET_OS=linux + LEVELDB_TARGET_FLAGS="-DOS_LINUX" + ;; + *) + OTHER_OS=`echo ${host_os} | awk '{print toupper($0)}'` + LEVELDB_TARGET_FLAGS="-DOS_${OTHER_OS}" + ;; +esac + +if test x$use_comparison_tool != xno; then + AC_SUBST(JAVA_COMPARISON_TOOL, $use_comparison_tool) +fi + +if test x$use_comparison_tool_reorg_tests != xno; then + if test x$use_comparison_tool = x; then + AC_MSG_ERROR("comparison tool reorg tests but comparison tool was not specified") + fi + AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 1) +else + AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 0) +fi + +if test x$use_extended_rpc_tests != xno; then + AC_SUBST(EXTENDED_RPC_TESTS, -extended) +fi + +if test x$use_lcov = xyes; then + if test x$LCOV = x; then + AC_MSG_ERROR("lcov testing requested but lcov not found") + fi + if test x$GCOV = x; then + AC_MSG_ERROR("lcov testing requested but gcov not found") + fi + if test x$JAVA = x; then + AC_MSG_ERROR("lcov testing requested but java not found") + fi + if test x$PYTHON = x; then + AC_MSG_ERROR("lcov testing requested but python not found") + fi + if test x$GENHTML = x; then + AC_MSG_ERROR("lcov testing requested but genhtml not found") + fi + if test x$use_comparison_tool = x; then + AC_MSG_ERROR("lcov testing requested but comparison tool was not specified") + fi + LCOV="$LCOV --gcov-tool=$GCOV" + AX_CHECK_COMPILE_FLAG([--coverage],[CXXFLAGS="$CXXFLAGS --coverage"], + [AC_MSG_ERROR("lcov testing requested but --coverage flag does not work")]) +fi + +dnl Check for endianness +AC_C_BIGENDIAN + +dnl Check for pthread compile/link requirements +AX_PTHREAD + +# The following macro will add the necessary defines to bitcoin-config.h, but +# they also need to be passed down to any subprojects. Pull the results out of +# the cache and add them to CPPFLAGS. +AC_SYS_LARGEFILE +# detect POSIX or GNU variant of strerror_r +AC_FUNC_STRERROR_R + +if test x$ac_cv_sys_file_offset_bits != x && + test x$ac_cv_sys_file_offset_bits != xno && + test x$ac_cv_sys_file_offset_bits != xunknown; then + CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits" +fi + +if test x$ac_cv_sys_large_files != x && + test x$ac_cv_sys_large_files != xno && + test x$ac_cv_sys_large_files != xunknown; then + CPPFLAGS="$CPPFLAGS -D_LARGE_FILES=$ac_cv_sys_large_files" +fi + +AX_CHECK_LINK_FLAG([[-Wl,--large-address-aware]], [LDFLAGS="$LDFLAGS -Wl,--large-address-aware"]) + +AX_GCC_FUNC_ATTRIBUTE([visibility]) +AX_GCC_FUNC_ATTRIBUTE([dllexport]) +AX_GCC_FUNC_ATTRIBUTE([dllimport]) + +if test x$use_glibc_compat != xno; then + + #glibc absorbed clock_gettime in 2.17. librt (its previous location) is safe to link + #in anyway for back-compat. + AC_CHECK_LIB([rt],[clock_gettime],, AC_MSG_ERROR(lib missing)) + + #__fdelt_chk's params and return type have changed from long unsigned int to long int. + # See which one is present here. + AC_MSG_CHECKING(__fdelt_chk type) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#ifdef _FORTIFY_SOURCE + #undef _FORTIFY_SOURCE + #endif + #define _FORTIFY_SOURCE 2 + #include + extern "C" long unsigned int __fdelt_warn(long unsigned int);]],[[]])], + [ fdelt_type="long unsigned int"], + [ fdelt_type="long int"]) + AC_MSG_RESULT($fdelt_type) + AC_DEFINE_UNQUOTED(FDELT_TYPE, $fdelt_type,[parameter and return value type for __fdelt_chk]) +else + AC_SEARCH_LIBS([clock_gettime],[rt]) +fi + +if test x$TARGET_OS != xwindows; then + # All windows code is PIC, forcing it on just adds useless compile warnings + AX_CHECK_COMPILE_FLAG([-fPIC],[PIC_FLAGS="-fPIC"]) +fi + +if test x$use_hardening != xno; then + AX_CHECK_COMPILE_FLAG([-Wstack-protector],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -Wstack-protector"]) + AX_CHECK_COMPILE_FLAG([-fstack-protector-all],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fstack-protector-all"]) + + AX_CHECK_PREPROC_FLAG([-D_FORTIFY_SOURCE=2],[ + AX_CHECK_PREPROC_FLAG([-U_FORTIFY_SOURCE],[ + HARDENED_CPPFLAGS="$HARDENED_CPPFLAGS -U_FORTIFY_SOURCE" + ]) + HARDENED_CPPFLAGS="$HARDENED_CPPFLAGS -D_FORTIFY_SOURCE=2" + ]) + + AX_CHECK_LINK_FLAG([[-Wl,--dynamicbase]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--dynamicbase"]) + AX_CHECK_LINK_FLAG([[-Wl,--nxcompat]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--nxcompat"]) + AX_CHECK_LINK_FLAG([[-Wl,-z,relro]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,relro"]) + AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"]) + + if test x$TARGET_OS != xwindows; then + AX_CHECK_COMPILE_FLAG([-fPIE],[PIE_FLAGS="-fPIE"]) + AX_CHECK_LINK_FLAG([[-pie]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"]) + fi + + case $host in + *mingw*) + AC_CHECK_LIB([ssp], [main],, AC_MSG_ERROR(lib missing)) + ;; + esac +fi + +dnl this flag screws up non-darwin gcc even when the check fails. special-case it. +if test x$TARGET_OS = xdarwin; then + AX_CHECK_LINK_FLAG([[-Wl,-dead_strip]], [LDFLAGS="$LDFLAGS -Wl,-dead_strip"]) +fi + +AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h]) +AC_SEARCH_LIBS([getaddrinfo_a], [anl], [AC_DEFINE(HAVE_GETADDRINFO_A, 1, [Define this symbol if you have getaddrinfo_a])]) +AC_SEARCH_LIBS([inet_pton], [nsl resolv], [AC_DEFINE(HAVE_INET_PTON, 1, [Define this symbol if you have inet_pton])]) + +AC_CHECK_DECLS([strnlen]) + +AC_CHECK_DECLS([le16toh, le32toh, le64toh, htole16, htole32, htole64, be16toh, be32toh, be64toh, htobe16, htobe32, htobe64],,, + [#if HAVE_ENDIAN_H + #include + #elif HAVE_SYS_ENDIAN_H + #include + #endif]) + +AC_CHECK_DECLS([bswap_16, bswap_32, bswap_64],,, + [#if HAVE_BYTESWAP_H + #include + #endif]) + +dnl Check for MSG_NOSIGNAL +AC_MSG_CHECKING(for MSG_NOSIGNAL) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ int f = MSG_NOSIGNAL; ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MSG_NOSIGNAL, 1,[Define this symbol if you have MSG_NOSIGNAL]) ], + [ AC_MSG_RESULT(no)] +) + +AC_MSG_CHECKING([for visibility attribute]) +AC_LINK_IFELSE([AC_LANG_SOURCE([ + int foo_def( void ) __attribute__((visibility("default"))); + int main(){} + ])], + [ + AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE,1,[Define if the visibility attribute is supported.]) + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_RESULT(no) + if test x$use_reduce_exports = xyes; then + AC_MSG_ERROR([Cannot find a working visibility attribute. Use --disable-reduce-exports.]) + fi + ] +) + +if test x$use_reduce_exports = xyes; then + AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[RE_CXXFLAGS="-fvisibility=hidden"], + [AC_MSG_ERROR([Cannot set default symbol visibility. Use --disable-reduce-exports.])]) +fi + +dnl This can go away when we require c++11 +TEMP_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS -std=c++0x" +AC_MSG_CHECKING(for c++11 atomics) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + ]],[[]])], + [ AC_MSG_RESULT(yes); LEVELDB_ATOMIC_CPPFLAGS="-DLEVELDB_ATOMIC_PRESENT"; LEVELDB_ATOMIC_CXXFLAGS="-std=c++0x"], + [ AC_MSG_RESULT(no)] +) +CXXFLAGS="$TEMP_CXXFLAGS" + +LEVELDB_CPPFLAGS= +LIBLEVELDB= +LIBMEMENV= +AM_CONDITIONAL([EMBEDDED_LEVELDB],[true]) +AC_SUBST(LEVELDB_CPPFLAGS) +AC_SUBST(LIBLEVELDB) +AC_SUBST(LIBMEMENV) + +if test x$enable_wallet != xno; then + dnl Check for libdb_cxx only if wallet enabled + BITCOIN_FIND_BDB48 +fi + +dnl Check for libminiupnpc (optional) +if test x$use_upnp != xno; then + AC_CHECK_HEADERS( + [miniupnpc/miniwget.h miniupnpc/miniupnpc.h miniupnpc/upnpcommands.h miniupnpc/upnperrors.h], + [AC_CHECK_LIB([miniupnpc], [main],[MINIUPNPC_LIBS=-lminiupnpc], [have_miniupnpc=no])], + [have_miniupnpc=no] + ) +fi + +BITCOIN_QT_INIT + +if test x$build_bitcoin_utils$build_bitcoind$use_tests = xnonono; then + use_boost=no +else + use_boost=yes +fi + +if test x$use_boost = xyes; then + +dnl Check for boost libs +AX_BOOST_BASE +AX_BOOST_SYSTEM +AX_BOOST_FILESYSTEM +AX_BOOST_PROGRAM_OPTIONS +AX_BOOST_THREAD +AX_BOOST_CHRONO + + +if test x$use_reduce_exports = xyes; then + AC_MSG_CHECKING([for working boost reduced exports]) + TEMP_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$BOOST_CPPFLAGS $CPPFLAGS" + AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[ + @%:@include + ]], [[ + #if BOOST_VERSION >= 104900 + // Everything is okay + #else + # error Boost version is too old + #endif + ]])],[ + AC_MSG_RESULT(yes) + ],[ + AC_MSG_ERROR([boost versions < 1.49 are known to be broken with reduced exports. Use --disable-reduce-exports.]) + ]) + CPPFLAGS="$TEMP_CPPFLAGS" +fi +fi + +if test x$use_reduce_exports = xyes; then + CXXFLAGS="$CXXFLAGS $RE_CXXFLAGS" + AX_CHECK_LINK_FLAG([[-Wl,--exclude-libs,ALL]], [RELDFLAGS="-Wl,--exclude-libs,ALL"]) +fi + +if test x$use_tests = xyes; then + + if test x$HEXDUMP = x; then + AC_MSG_ERROR(hexdump is required for tests) + fi + + + if test x$use_boost = xyes; then + + AX_BOOST_UNIT_TEST_FRAMEWORK + + dnl Determine if -DBOOST_TEST_DYN_LINK is needed + AC_MSG_CHECKING([for dynamic linked boost test]) + TEMP_LIBS="$LIBS" + LIBS="$LIBS $BOOST_LDFLAGS $BOOST_UNIT_TEST_FRAMEWORK_LIB" + TEMP_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + AC_LINK_IFELSE([AC_LANG_SOURCE([ + #define BOOST_TEST_DYN_LINK + #define BOOST_TEST_MAIN + #include + + ])], + [AC_MSG_RESULT(yes)] + [TESTDEFS="$TESTDEFS -DBOOST_TEST_DYN_LINK"], + [AC_MSG_RESULT(no)]) + LIBS="$TEMP_LIBS" + CPPFLAGS="$TEMP_CPPFLAGS" + + fi +fi + +if test x$use_boost = xyes; then + +BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB" + +dnl Boost >= 1.50 uses sleep_for rather than the now-deprecated sleep, however +dnl it was broken from 1.50 to 1.52 when backed by nanosleep. Use sleep_for if +dnl a working version is available, else fall back to sleep. sleep was removed +dnl after 1.56. +dnl If neither is available, abort. +TEMP_LIBS="$LIBS" +LIBS="$BOOST_LIBS $LIBS" +TEMP_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + ]],[[ + #if BOOST_VERSION >= 105000 && (!defined(BOOST_HAS_NANOSLEEP) || BOOST_VERSION >= 105200) + boost::this_thread::sleep_for(boost::chrono::milliseconds(0)); + #else + choke me + #endif + ]])], + [boost_sleep=yes; + AC_DEFINE(HAVE_WORKING_BOOST_SLEEP_FOR, 1, [Define this symbol if boost sleep_for works])], + [boost_sleep=no]) +LIBS="$TEMP_LIBS" +CPPFLAGS="$TEMP_CPPFLAGS" + +if test x$boost_sleep != xyes; then +TEMP_LIBS="$LIBS" +LIBS="$BOOST_LIBS $LIBS" +TEMP_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + #include + ]],[[ + #if BOOST_VERSION <= 105600 + boost::this_thread::sleep(boost::posix_time::milliseconds(0)); + #else + choke me + #endif + ]])], + [boost_sleep=yes; AC_DEFINE(HAVE_WORKING_BOOST_SLEEP, 1, [Define this symbol if boost sleep works])], + [boost_sleep=no]) +LIBS="$TEMP_LIBS" +CPPFLAGS="$TEMP_CPPFLAGS" +fi + +if test x$boost_sleep != xyes; then + AC_MSG_ERROR(No working boost sleep implementation found.) +fi + +fi + +if test x$use_pkgconfig = xyes; then + + if test x"$PKG_CONFIG" = "x"; then + AC_MSG_ERROR(pkg-config not found.) + fi + + : #NOP + m4_ifdef( + [PKG_CHECK_MODULES], + [ + PKG_CHECK_MODULES([SSL], [libssl],, [AC_MSG_ERROR(openssl not found.)]) + PKG_CHECK_MODULES([CRYPTO], [libcrypto],,[AC_MSG_ERROR(libcrypto not found.)]) + BITCOIN_QT_CHECK([PKG_CHECK_MODULES([PROTOBUF], [protobuf], [have_protobuf=yes], [BITCOIN_QT_FAIL(libprotobuf not found)])]) + if test x$use_qr != xno; then + BITCOIN_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])]) + fi + if test x$build_bitcoin_utils$build_bitcoind$use_tests != xnonono; then + PKG_CHECK_MODULES([EVENT], [libevent],, [AC_MSG_ERROR(libevent not found.)]) + if test x$TARGET_OS != xwindows; then + PKG_CHECK_MODULES([EVENT_PTHREADS], [libevent_pthreads],, [AC_MSG_ERROR(libevent_pthreads not found.)]) + fi + fi + ] + ) +else + AC_CHECK_HEADER([openssl/crypto.h],,AC_MSG_ERROR(libcrypto headers missing)) + AC_CHECK_LIB([crypto], [main],CRYPTO_LIBS=-lcrypto, AC_MSG_ERROR(libcrypto missing)) + + AC_CHECK_HEADER([openssl/ssl.h],, AC_MSG_ERROR(libssl headers missing),) + AC_CHECK_LIB([ssl], [main],SSL_LIBS=-lssl, AC_MSG_ERROR(libssl missing)) + + if test x$build_bitcoin_utils$build_bitcoind$use_tests != xnonono; then + AC_CHECK_HEADER([event2/event.h],, AC_MSG_ERROR(libevent headers missing),) + AC_CHECK_LIB([event],[main],EVENT_LIBS=-levent,AC_MSG_ERROR(libevent missing)) + if test x$TARGET_OS != xwindows; then + AC_CHECK_LIB([event_pthreads],[main],EVENT_PTHREADS_LIBS=-levent_pthreads,AC_MSG_ERROR(libevent_pthreads missing)) + fi + fi + + if test x$use_qr != xno; then + BITCOIN_QT_CHECK([AC_CHECK_LIB([qrencode], [main],[QR_LIBS=-lqrencode], [have_qrencode=no])]) + BITCOIN_QT_CHECK([AC_CHECK_HEADER([qrencode.h],, have_qrencode=no)]) + fi +fi + +CXXFLAGS_TEMP="$CXXFLAGS" +LIBS_TEMP="$LIBS" +CXXFLAGS="$CXXFLAGS $SSL_CFLAGS $CRYPTO_CFLAGS" +LIBS="$LIBS $SSL_LIBS $CRYPTO_LIBS" +AC_CHECK_HEADER([openssl/ec.h],, AC_MSG_ERROR(OpenSSL ec header missing),) +CXXFLAGS="$CXXFLAGS_TEMP" +LIBS="$LIBS_TEMP" + +BITCOIN_QT_PATH_PROGS([PROTOC], [protoc],$protoc_bin_path) + +AC_MSG_CHECKING([whether to build bitcoind]) +AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes]) +AC_MSG_RESULT($build_bitcoind) + +AC_MSG_CHECKING([whether to build utils (bitcoin-cli bitcoin-tx)]) +AM_CONDITIONAL([BUILD_BITCOIN_UTILS], [test x$build_bitcoin_utils = xyes]) +AC_MSG_RESULT($build_bitcoin_utils) + +AC_MSG_CHECKING([whether to build libraries]) +AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test x$build_bitcoin_libs = xyes]) +if test x$build_bitcoin_libs = xyes; then + AC_DEFINE(HAVE_CONSENSUS_LIB, 1, [Define this symbol if the consensus lib has been built]) + AC_CONFIG_FILES([libbitcoinconsensus.pc:libbitcoinconsensus.pc.in]) +fi +AC_MSG_RESULT($build_bitcoin_libs) + +AC_LANG_POP + +if test "x$use_ccache" != "xno"; then + AC_MSG_CHECKING(if ccache should be used) + if test x$CCACHE = x; then + if test "x$use_ccache" = "xyes"; then + AC_MSG_ERROR([ccache not found.]); + else + use_ccache=no + fi + else + use_ccache=yes + CC="$ac_cv_path_CCACHE $CC" + CXX="$ac_cv_path_CCACHE $CXX" + fi + AC_MSG_RESULT($use_ccache) +fi +if test "x$use_ccache" = "xyes"; then + AX_CHECK_PREPROC_FLAG([-Qunused-arguments],[CPPFLAGS="-Qunused-arguments $CPPFLAGS"]) +fi + +dnl enable wallet +AC_MSG_CHECKING([if wallet should be enabled]) +if test x$enable_wallet != xno; then + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED([ENABLE_WALLET],[1],[Define to 1 to enable wallet functions]) + +else + AC_MSG_RESULT(no) +fi + +dnl enable upnp support +AC_MSG_CHECKING([whether to build with support for UPnP]) +if test x$have_miniupnpc = xno; then + if test x$use_upnp = xyes; then + AC_MSG_ERROR("UPnP requested but cannot be built. use --without-miniupnpc") + fi + AC_MSG_RESULT(no) +else + if test x$use_upnp != xno; then + AC_MSG_RESULT(yes) + AC_MSG_CHECKING([whether to build with UPnP enabled by default]) + use_upnp=yes + upnp_setting=0 + if test x$use_upnp_default != xno; then + use_upnp_default=yes + upnp_setting=1 + fi + AC_MSG_RESULT($use_upnp_default) + AC_DEFINE_UNQUOTED([USE_UPNP],[$upnp_setting],[UPnP support not compiled if undefined, otherwise value (0 or 1) determines default state]) + if test x$TARGET_OS = xwindows; then + MINIUPNPC_CPPFLAGS="-DSTATICLIB -DMINIUPNP_STATICLIB" + fi + else + AC_MSG_RESULT(no) + fi +fi + +AC_MSG_CHECKING([whether to build test_bitcoin]) +if test x$use_tests = xyes; then + AC_MSG_RESULT([yes]) + BUILD_TEST="yes" +else + AC_MSG_RESULT([no]) + BUILD_TEST="" +fi + +AC_MSG_CHECKING([whether to reduce exports]) +if test x$use_reduce_exports = xyes; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +if test x$build_bitcoin_utils$build_bitcoin_libs$build_bitcoind$use_tests = xnononono; then + AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui or --enable-tests]) +fi + +AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) +AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) +AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) +AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) +AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) +AM_CONDITIONAL([ENABLE_BENCH],[test x$use_bench = xyes]) +AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes]) +AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes]) +AM_CONDITIONAL([USE_COMPARISON_TOOL],[test x$use_comparison_tool != xno]) +AM_CONDITIONAL([USE_COMPARISON_TOOL_REORG_TESTS],[test x$use_comparison_tool_reorg_test != xno]) +AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) +AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes]) + +AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version]) +AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version]) +AC_DEFINE(CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION, [Build revision]) +AC_DEFINE(CLIENT_VERSION_BUILD, _CLIENT_VERSION_BUILD, [Version Build]) +AC_DEFINE(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE, [Version is release]) +AC_DEFINE(COPYRIGHT_YEAR, _COPYRIGHT_YEAR, [Version is release]) +AC_SUBST(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR) +AC_SUBST(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR) +AC_SUBST(CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION) +AC_SUBST(CLIENT_VERSION_BUILD, _CLIENT_VERSION_BUILD) +AC_SUBST(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE) +AC_SUBST(COPYRIGHT_YEAR, _COPYRIGHT_YEAR) + +AC_SUBST(RELDFLAGS) +AC_SUBST(HARDENED_CXXFLAGS) +AC_SUBST(HARDENED_CPPFLAGS) +AC_SUBST(HARDENED_LDFLAGS) +AC_SUBST(PIC_FLAGS) +AC_SUBST(PIE_FLAGS) +AC_SUBST(LIBTOOL_APP_LDFLAGS) +AC_SUBST(USE_UPNP) +AC_SUBST(USE_QRCODE) +AC_SUBST(BOOST_LIBS) +AC_SUBST(TESTDEFS) +AC_SUBST(LEVELDB_TARGET_FLAGS) +AC_SUBST(MINIUPNPC_CPPFLAGS) +AC_SUBST(MINIUPNPC_LIBS) +AC_SUBST(LEVELDB_ATOMIC_CPPFLAGS) +AC_SUBST(LEVELDB_ATOMIC_CXXFLAGS) +AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi src/test/buildenv.py]) +AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh]) +AC_CONFIG_FILES([qa/pull-tester/tests_config.py],[chmod +x qa/pull-tester/tests_config.py]) + +dnl boost's m4 checks do something really nasty: they export these vars. As a +dnl result, they leak into secp256k1's configure and crazy things happen. +dnl Until this is fixed upstream and we've synced, we'll just un-export them. +CPPFLAGS_TEMP="$CPPFLAGS" +unset CPPFLAGS +CPPFLAGS="$CPPFLAGS_TEMP" + +LDFLAGS_TEMP="$LDFLAGS" +unset LDFLAGS +LDFLAGS="$LDFLAGS_TEMP" + +LIBS_TEMP="$LIBS" +unset LIBS +LIBS="$LIBS_TEMP" + +PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" +unset PKG_CONFIG_PATH +PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP" + +PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR" +unset PKG_CONFIG_LIBDIR +PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" + +ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery" +AC_CONFIG_SUBDIRS([src/secp256k1]) + +AC_OUTPUT + +dnl Taken from https://wiki.debian.org/RpathIssue +case $host in + *-*-linux-gnu) + AC_MSG_RESULT([Fixing libtool for -rpath problems.]) + sed < libtool > libtool-2 \ + 's/^hardcode_libdir_flag_spec.*$'/'hardcode_libdir_flag_spec=" -D__LIBTOOL_IS_A_FOOL__ "/' + mv libtool-2 libtool + chmod 755 libtool + ;; +esac + +dnl Replace the BUILDDIR path with the correct Windows path if compiling on Native Windows +case ${OS} in + *Windows*) + sed 's/BUILDDIR="\/\([[a-z]]\)/BUILDDIR="\1:/' qa/pull-tester/tests_config.py > qa/pull-tester/tests_config-2.py + mv qa/pull-tester/tests_config-2.py qa/pull-tester/tests_config.py + ;; +esac + +echo +echo "Options used to compile and link:" +echo " with wallet = $enable_wallet" +echo " with test = $use_tests" +echo " with bench = $use_bench" +echo " with upnp = $use_upnp" +echo " debug enabled = $enable_debug" +echo +echo " target os = $TARGET_OS" +echo " build os = $BUILD_OS" +echo +echo " CC = $CC" +echo " CFLAGS = $CFLAGS" +echo " CPPFLAGS = $CPPFLAGS" +echo " CXX = $CXX" +echo " CXXFLAGS = $CXXFLAGS" +echo " LDFLAGS = $LDFLAGS" +echo diff --git a/contrib/cmake/CMakeLists.txt b/contrib/cmake/CMakeLists.txt new file mode 100644 index 00000000..9a20162e --- /dev/null +++ b/contrib/cmake/CMakeLists.txt @@ -0,0 +1,117 @@ +# ECC Build System +# +# This CMakeLists.txt is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Fixes +set(CONTRIB_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +string(REGEX REPLACE "/contrib/cmake" "" CMAKE_CURRENT_SOURCE_DIR + ${CMAKE_CURRENT_SOURCE_DIR}) + +# CMake version +cmake_minimum_required(VERSION 3.0 FATAL_ERROR) + +# Include CMake Modules +list(APPEND CMAKE_MODULE_PATH "${CONTRIB_CURRENT_SOURCE_DIR}/modules") + +include(Custom) + +# Set policies +set_policy(CMP0028 NEW) # ENABLE CMP0028: Double colon in target name means ALIAS or IMPORTED target. +set_policy(CMP0054 NEW) # ENABLE CMP0054: Only interpret if() arguments as variables or keywords when unquoted. +set_policy(CMP0042 NEW) # ENABLE CMP0042: MACOSX_RPATH is enabled by default. +set_policy(CMP0063 NEW) # ENABLE CMP0063: Honor visibility properties for all target types. + +include(GetGitRevisionDescription) +include(HealthCheck) +include(cotire) +include(ucm) + +# +# Generate Project Information +# +# Get git revision +get_git_head_revision(GIT_REFSPEC GIT_SHA1) +string(SUBSTRING "${GIT_SHA1}" 0 12 GIT_REV) +if(NOT GIT_SHA1) + set(GIT_REV "0") +endif() + +# Meta information about the project +set(META_PROJECT_NAME "ECC") +set(META_PROJECT_DESCRIPTION "ECC Descentralized Coin") +set(META_AUTHOR_ORGANIZATION "ECC Project") +set(META_AUTHOR_DOMAIN "https://github.com/brunoalano/eccoin/") +set(META_AUTHOR_MAINTAINER "opensource@ecc.network") +set(META_VERSION_MAJOR "1") +set(META_VERSION_MINOR "0") +set(META_VERSION_PATCH "0") +set(META_VERSION_REVISION "${GIT_REV}") +set(META_VERSION "${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}") +set(META_NAME_VERSION "${META_PROJECT_NAME} v${META_VERSION} (${META_VERSION_REVISION})") +set(META_CMAKE_INIT_SHA "${GIT_SHA1}") +string(MAKE_C_IDENTIFIER ${META_PROJECT_NAME} META_PROJECT_ID) +string(TOUPPER ${META_PROJECT_ID} META_PROJECT_ID) + +# +# Project configuration options +# + +# Project options +option(OPTION_BUILD_TESTS "Build tests." ON) +option(OPTION_BUILD_DOCS "Build documentation." OFF) + +# +# Declare project +# + +# Generate folders for IDE targets (e.g., VisualStudio solutions) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set(IDE_FOLDER "") + +# Declare project +project(${META_PROJECT_NAME} C CXX) + +# Set output directories +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + +# Create version file +file(WRITE "${PROJECT_BINARY_DIR}/VERSION" "${META_NAME_VERSION}") + +# +# Compiler settings and options +# +include(CompileOptions) +ucm_add_flags(CXX ${DEFAULT_COMPILE_OPTIONS}) +ucm_add_linker_flags(${DEFAULT_LINKER_OPTIONS}) + +# Configure health check tools +enable_cppcheck(On) +enable_clang_tidy(On) + +# Check for C++11/14 support +project_check_cpp_version() +check_cxx_compiler_flag( "-std=c++11" COMPILER_SUPPORTS_CXX11 ) +check_cxx_compiler_flag( "-std=c++0x" COMPILER_SUPPORTS_CXX0X ) +if( COMPILER_SUPPORTS_CXX11 ) + if( CMAKE_COMPILER_IS_GNUCXX ) + ucm_add_flags( CXX -std=gnu++11 ) + else() + ucm_add_flags( CXX -std=c++11 ) + endif() +elseif( COMPILER_SUPPORTS_CXX0X) + ucm_add_flags( -std=c++0x ) +else() + # MSVC, On by default (if available) +endif() + +# Append the `src` +add_subdirectory(src) \ No newline at end of file diff --git a/contrib/cmake/modules/ClangTidy.cmake b/contrib/cmake/modules/ClangTidy.cmake new file mode 100644 index 00000000..3e01032b --- /dev/null +++ b/contrib/cmake/modules/ClangTidy.cmake @@ -0,0 +1,24 @@ + +# Function to register a target for clang-tidy +function(perform_clang_tidy check_target target) + set(includes "$") + + add_custom_target( + ${check_target} + COMMAND + ${clang_tidy_EXECUTABLE} + -p\t${PROJECT_BINARY_DIR} + ${ARGN} + -checks=* + "$<$>:--\t$<$:-I$>>" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + set_target_properties(${check_target} + PROPERTIES + FOLDER "Maintenance" + EXCLUDE_FROM_DEFAULT_BUILD 1 + ) + + add_dependencies(${check_target} ${target}) +endfunction() diff --git a/contrib/cmake/modules/CompileOptions.cmake b/contrib/cmake/modules/CompileOptions.cmake new file mode 100644 index 00000000..d108dc1c --- /dev/null +++ b/contrib/cmake/modules/CompileOptions.cmake @@ -0,0 +1,123 @@ + +# +# Platform and architecture setup +# + +# Get upper case system name +string(TOUPPER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME_UPPER) + +# Determine architecture (32/64 bit) +set(X64 OFF) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(X64 ON) +endif() + + +# +# Project options +# + +set(DEFAULT_PROJECT_OPTIONS + DEBUG_POSTFIX "d" + CXX_STANDARD 11 # Not available before CMake 3.1; see below for manual command line argument addition + LINKER_LANGUAGE "CXX" + POSITION_INDEPENDENT_CODE ON + CXX_VISIBILITY_PRESET "hidden" +) + + +# +# Include directories +# + +set(DEFAULT_INCLUDE_DIRECTORIES) + + +# +# Libraries +# + +set(DEFAULT_LIBRARIES) + + +# +# Compile definitions +# + +set(DEFAULT_COMPILE_DEFINITIONS + SYSTEM_${SYSTEM_NAME_UPPER} +) + +# MSVC compiler options +if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC") + set(DEFAULT_COMPILE_DEFINITIONS ${DEFAULT_COMPILE_DEFINITIONS} + _SCL_SECURE_NO_WARNINGS # Calling any one of the potentially unsafe methods in the Standard C++ Library + _CRT_SECURE_NO_WARNINGS # Calling any one of the potentially unsafe methods in the CRT Library + ) +endif () + + +# +# Compile options +# + +set(DEFAULT_COMPILE_OPTIONS) + +# MSVC compiler options +if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC") + set(DEFAULT_COMPILE_OPTIONS ${DEFAULT_COMPILE_OPTIONS} + /MP # -> build with multiple processes + /W4 # -> warning level 4 + # /WX # -> treat warnings as errors + + /wd4251 # -> disable warning: 'identifier': class 'type' needs to have dll-interface to be used by clients of class 'type2' + /wd4592 # -> disable warning: 'identifier': symbol will be dynamically initialized (implementation limitation) + # /wd4201 # -> disable warning: nonstandard extension used: nameless struct/union (caused by GLM) + # /wd4127 # -> disable warning: conditional expression is constant (caused by Qt) + + #$<$: + #/RTCc # -> value is assigned to a smaller data type and results in a data loss + #> + + $<$: + /Gw # -> whole program global optimization + /GS- # -> buffer security check: no + /GL # -> whole program optimization: enable link-time code generation (disables Zi) + /GF # -> enable string pooling + > + + # No manual c++11 enable for MSVC as all supported MSVC versions for cmake-init have C++11 implicitly enabled (MSVC >=2013) + ) +endif () + +# GCC and Clang compiler options +if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + set(DEFAULT_COMPILE_OPTIONS ${DEFAULT_COMPILE_OPTIONS} + -Wall + -Wextra + -Wunused + + -Wreorder + -Wignored-qualifiers + -Wmissing-braces + -Wreturn-type + -Wswitch + -Wswitch-default + -Wuninitialized + -Wmissing-field-initializers + ) +endif () + + +# +# Linker options +# + +set(DEFAULT_LINKER_OPTIONS) + +# Use pthreads on mingw and linux +if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU" OR "${CMAKE_SYSTEM_NAME}" MATCHES "Linux") + set(DEFAULT_LINKER_OPTIONS + -pthread + ) +endif() diff --git a/contrib/cmake/modules/Cppcheck.cmake b/contrib/cmake/modules/Cppcheck.cmake new file mode 100644 index 00000000..1f9ac05b --- /dev/null +++ b/contrib/cmake/modules/Cppcheck.cmake @@ -0,0 +1,26 @@ + +# Function to register a target for cppcheck +function(perform_cppcheck check_target target) + set(includes "$") + + add_custom_target( + ${check_target} + COMMAND + ${cppcheck_EXECUTABLE} + "$<$:-I$>" + --enable=all + --std=c++11 + --verbose + --suppress=missingIncludeSystem + ${ARGN} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + set_target_properties(${check_target} + PROPERTIES + FOLDER "Maintenance" + EXCLUDE_FROM_DEFAULT_BUILD 1 + ) + + add_dependencies(${check_target} ${target}) +endfunction() diff --git a/contrib/cmake/modules/Custom.cmake b/contrib/cmake/modules/Custom.cmake new file mode 100644 index 00000000..5f5bca4b --- /dev/null +++ b/contrib/cmake/modules/Custom.cmake @@ -0,0 +1,43 @@ +# ECC Utilities + +include(CheckCXXCompilerFlag) + +# Set policy if policy is available +function(set_policy POL VAL) + if(POLICY ${POL}) + cmake_policy(SET ${POL} ${VAL}) + endif() +endfunction(set_policy) + +# Check C++ version +macro(project_check_cpp_version) + if (NOT MSVC) + # Tests for Clang and GCC + check_cxx_compiler_flag(-std=c++1y CPP14_SUPPORT) + if (CPP14_SUPPORT) + set(CPP11_SUPPORT TRUE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y") + message("-- C++14 support found.") + else() + check_cxx_compiler_flag(-std=c++11 CPP11_SUPPORT) + if (CPP11_SUPPORT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + message("-- C++11 support found.") + endif() + endif() + else() + # Tests for MSVC + # Unfortunately, due to various unsupported things in msvc versions, + # this is poor informatiion about actual support + check_cxx_source_compiles("#include \nusing std::integer_sequence;\n int main(){return 0;}" CPP14_SUPPORT) + if (CPP14_SUPPORT) + set(CPP11_SUPPORT TRUE) + message("-- C++14 support found.") + else() + check_cxx_source_compiles("static constexpr int TEST=0;\n int main(){return 0;}" CPP11_SUPPORT) + if (CPP11_SUPPORT) + message("-- C++11 support found.") + endif() + endif () + endif() +endmacro(project_check_cpp_version) \ No newline at end of file diff --git a/contrib/cmake/modules/FindBerkeleyDB.cmake b/contrib/cmake/modules/FindBerkeleyDB.cmake new file mode 100644 index 00000000..c6ff9b95 --- /dev/null +++ b/contrib/cmake/modules/FindBerkeleyDB.cmake @@ -0,0 +1,24 @@ +# - Try to find Berkeley DB +# Once done this will define +# +# BERKELEY_DB_FOUND - system has Berkeley DB +# BERKELEY_DB_INCLUDE_DIR - the Berkeley DB include directory +# BERKELEY_DB_LIBRARIES - Link these to use Berkeley DB +# BERKELEY_DB_DEFINITIONS - Compiler switches required for using Berkeley DB + +# Copyright (c) 2006, Alexander Dymo, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +find_path(BERKELEY_DB_INCLUDE_DIR db_cxx.h + /usr/include/db4 + /usr/local/include/db4 +) + +find_library(BERKELEY_DB_LIBRARIES NAMES db_cxx ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Berkeley "Could not find Berkeley DB >= 4.1" BERKELEY_DB_INCLUDE_DIR BERKELEY_DB_LIBRARIES) +# show the BERKELEY_DB_INCLUDE_DIR and BERKELEY_DB_LIBRARIES variables only in the advanced view +mark_as_advanced(BERKELEY_DB_INCLUDE_DIR BERKELEY_DB_LIBRARIES ) diff --git a/contrib/cmake/modules/FindLibEvent.cmake b/contrib/cmake/modules/FindLibEvent.cmake new file mode 100644 index 00000000..8b320186 --- /dev/null +++ b/contrib/cmake/modules/FindLibEvent.cmake @@ -0,0 +1,37 @@ +# - Find LibEvent (a cross event library) +# This module defines +# LIBEVENT_INCLUDE_DIR, where to find LibEvent headers +# LIBEVENT_LIB, LibEvent libraries +# LibEvent_FOUND, If false, do not try to use libevent + +set(LibEvent_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}") +foreach(prefix ${LibEvent_EXTRA_PREFIXES}) + list(APPEND LibEvent_INCLUDE_PATHS "${prefix}/include") + list(APPEND LibEvent_LIB_PATHS "${prefix}/lib") +endforeach() + +find_path(LIBEVENT_INCLUDE_DIR event.h PATHS ${LibEvent_INCLUDE_PATHS}) +find_library(LIBEVENT_LIB NAMES event PATHS ${LibEvent_LIB_PATHS}) + +if (LIBEVENT_LIB AND LIBEVENT_INCLUDE_DIR) + set(LibEvent_FOUND TRUE) + set(LIBEVENT_LIB ${LIBEVENT_LIB}) +else () + set(LibEvent_FOUND FALSE) +endif () + +if (LibEvent_FOUND) + if (NOT LibEvent_FIND_QUIETLY) + message(STATUS "Found libevent: ${LIBEVENT_LIB}") + endif () +else () + if (LibEvent_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find libevent.") + endif () + message(STATUS "libevent NOT found.") +endif () + +mark_as_advanced( + LIBEVENT_LIB + LIBEVENT_INCLUDE_DIR + ) \ No newline at end of file diff --git a/contrib/cmake/modules/Findclang_tidy.cmake b/contrib/cmake/modules/Findclang_tidy.cmake new file mode 100644 index 00000000..c29dfcdf --- /dev/null +++ b/contrib/cmake/modules/Findclang_tidy.cmake @@ -0,0 +1,28 @@ + +# Findclang_tidy results: +# clang_tidy_FOUND +# clang_tidy_EXECUTABLE + +include(FindPackageHandleStandardArgs) + +find_program(clang_tidy_EXECUTABLE + NAMES + clang-tidy-3.5 + clang-tidy-3.6 + clang-tidy-3.7 + clang-tidy-3.8 + clang-tidy-3.9 + clang-tidy-4.0 + clang-tidy + PATHS + "${CLANG_TIDY_DIR}" +) + +find_package_handle_standard_args(clang_tidy + FOUND_VAR + clang_tidy_FOUND + REQUIRED_VARS + clang_tidy_EXECUTABLE +) + +mark_as_advanced(clang_tidy_EXECUTABLE) \ No newline at end of file diff --git a/contrib/cmake/modules/Findcppcheck.cmake b/contrib/cmake/modules/Findcppcheck.cmake new file mode 100644 index 00000000..c90e7cd0 --- /dev/null +++ b/contrib/cmake/modules/Findcppcheck.cmake @@ -0,0 +1,28 @@ + +# Findcppcheck results: +# cppcheck_FOUND +# cppcheck_EXECUTABLE + +include(FindPackageHandleStandardArgs) + +# work around CMP0053, see http://public.kitware.com/pipermail/cmake/2014-November/059117.html +set(PROGRAMFILES_x86_ENV "PROGRAMFILES(x86)") + +find_program(cppcheck_EXECUTABLE + NAMES + cppcheck + PATHS + "${CPPCHECK_DIR}" + "$ENV{CPPCHECK_DIR}" + "$ENV{PROGRAMFILES}/Cppcheck" + "$ENV{${PROGRAMFILES_x86_ENV}}/Cppcheck" +) + +find_package_handle_standard_args(cppcheck + FOUND_VAR + cppcheck_FOUND + REQUIRED_VARS + cppcheck_EXECUTABLE +) + +mark_as_advanced(cppcheck_EXECUTABLE) diff --git a/contrib/cmake/modules/GetGitRevisionDescription.cmake b/contrib/cmake/modules/GetGitRevisionDescription.cmake new file mode 100644 index 00000000..85eae156 --- /dev/null +++ b/contrib/cmake/modules/GetGitRevisionDescription.cmake @@ -0,0 +1,130 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ ...]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +function(get_git_head_revision _refspecvar _hashvar) + set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories + set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") + get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) + if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) + # We have reached the root directory, we are not in git + set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + return() + endif() + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + endwhile() + # check if this is a submodule + if(NOT IS_DIRECTORY ${GIT_DIR}) + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${GIT_DIR}/HEAD") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" + @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) + set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + describe + ${hash} + ${ARGN} + WORKING_DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() diff --git a/contrib/cmake/modules/GetGitRevisionDescription.cmake.in b/contrib/cmake/modules/GetGitRevisionDescription.cmake.in new file mode 100644 index 00000000..6d8b708e --- /dev/null +++ b/contrib/cmake/modules/GetGitRevisionDescription.cmake.in @@ -0,0 +1,41 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + else() + configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) + file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) + if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") + set(HEAD_HASH "${CMAKE_MATCH_1}") + endif() + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() diff --git a/contrib/cmake/modules/HealthCheck.cmake b/contrib/cmake/modules/HealthCheck.cmake new file mode 100644 index 00000000..8df8b9a3 --- /dev/null +++ b/contrib/cmake/modules/HealthCheck.cmake @@ -0,0 +1,104 @@ + +include(${CMAKE_CURRENT_LIST_DIR}/Cppcheck.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/ClangTidy.cmake) + +set(OPTION_CPPCHECK_ENABLED Off) +set(OPTION_CLANG_TIDY_ENABLED Off) + +# Function to register a target for enabled health checks +function(perform_health_checks target) + if(NOT TARGET check-all) + add_custom_target(check-all) + + set_target_properties(check-all + PROPERTIES + FOLDER "Maintenance" + EXCLUDE_FROM_DEFAULT_BUILD 1 + ) + endif() + + add_custom_target(check-${target}) + + set_target_properties(check-${target} + PROPERTIES + FOLDER "Maintenance" + EXCLUDE_FROM_DEFAULT_BUILD 1 + ) + + if (OPTION_CPPCHECK_ENABLED) + perform_cppcheck(cppcheck-${target} ${target} ${ARGN}) + add_dependencies(check-${target} cppcheck-${target}) + endif() + + if (OPTION_CLANG_TIDY_ENABLED) + perform_clang_tidy(clang-tidy-${target} ${target} ${ARGN}) + add_dependencies(check-${target} clang-tidy-${target}) + endif() + + add_dependencies(check-all check-${target}) +endfunction() + +# Enable or disable cppcheck for health checks +function(enable_cppcheck status) + if(NOT ${status}) + set(OPTION_CPPCHECK_ENABLED ${status} PARENT_SCOPE) + message(STATUS "Check cppcheck skipped: Manually disabled") + + return() + endif() + + find_package(cppcheck) + + if(NOT cppcheck_FOUND) + set(OPTION_CPPCHECK_ENABLED Off PARENT_SCOPE) + message(STATUS "Check cppcheck skipped: cppcheck not found") + + return() + endif() + + set(OPTION_CPPCHECK_ENABLED ${status} PARENT_SCOPE) + message(STATUS "Check cppcheck") +endfunction() + +# Enable or disable clang-tidy for health checks +function(enable_clang_tidy status) + if(NOT ${status}) + set(OPTION_CLANG_TIDY_ENABLED ${status} PARENT_SCOPE) + message(STATUS "Check clang-tidy skipped: Manually disabled") + + return() + endif() + + find_package(clang_tidy) + + if(NOT clang_tidy_FOUND) + set(OPTION_CLANG_TIDY_ENABLED Off PARENT_SCOPE) + message(STATUS "Check clang-tidy skipped: clang-tidy not found") + + return() + endif() + + set(OPTION_CLANG_TIDY_ENABLED ${status} PARENT_SCOPE) + message(STATUS "Check clang-tidy") + + set(CMAKE_EXPORT_COMPILE_COMMANDS On PARENT_SCOPE) +endfunction() + +# Configure cmake target to check for cmake-init template +function(add_check_template_target current_template_sha) + add_custom_target( + check-template + COMMAND ${CMAKE_COMMAND} + -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} + -DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR} + -DAPPLIED_CMAKE_INIT_SHA=${current_template_sha} + -P ${PROJECT_SOURCE_DIR}/cmake/CheckTemplate.cmake + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + ) + + set_target_properties(check-template + PROPERTIES + FOLDER "Maintenance" + EXCLUDE_FROM_DEFAULT_BUILD 1 + ) +endfunction() diff --git a/contrib/cmake/modules/cotire.cmake b/contrib/cmake/modules/cotire.cmake new file mode 100644 index 00000000..a1e5ef08 --- /dev/null +++ b/contrib/cmake/modules/cotire.cmake @@ -0,0 +1,4054 @@ +# - cotire (compile time reducer) +# +# See the cotire manual for usage hints. +# +#============================================================================= +# Copyright 2012-2017 Sascha Kratky +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +#============================================================================= + +if(__COTIRE_INCLUDED) + return() +endif() +set(__COTIRE_INCLUDED TRUE) + +# call cmake_minimum_required, but prevent modification of the CMake policy stack in include mode +# cmake_minimum_required also sets the policy version as a side effect, which we have to avoid +if (NOT CMAKE_SCRIPT_MODE_FILE) + cmake_policy(PUSH) +endif() +cmake_minimum_required(VERSION 2.8.12) +if (NOT CMAKE_SCRIPT_MODE_FILE) + cmake_policy(POP) +endif() + +set (COTIRE_CMAKE_MODULE_FILE "${CMAKE_CURRENT_LIST_FILE}") +set (COTIRE_CMAKE_MODULE_VERSION "1.7.10") + +# activate select policies +if (POLICY CMP0025) + # Compiler id for Apple Clang is now AppleClang + cmake_policy(SET CMP0025 NEW) +endif() + +if (POLICY CMP0026) + # disallow use of the LOCATION target property + cmake_policy(SET CMP0026 NEW) +endif() + +if (POLICY CMP0038) + # targets may not link directly to themselves + cmake_policy(SET CMP0038 NEW) +endif() + +if (POLICY CMP0039) + # utility targets may not have link dependencies + cmake_policy(SET CMP0039 NEW) +endif() + +if (POLICY CMP0040) + # target in the TARGET signature of add_custom_command() must exist + cmake_policy(SET CMP0040 NEW) +endif() + +if (POLICY CMP0045) + # error on non-existent target in get_target_property + cmake_policy(SET CMP0045 NEW) +endif() + +if (POLICY CMP0046) + # error on non-existent dependency in add_dependencies + cmake_policy(SET CMP0046 NEW) +endif() + +if (POLICY CMP0049) + # do not expand variables in target source entries + cmake_policy(SET CMP0049 NEW) +endif() + +if (POLICY CMP0050) + # disallow add_custom_command SOURCE signatures + cmake_policy(SET CMP0050 NEW) +endif() + +if (POLICY CMP0051) + # include TARGET_OBJECTS expressions in a target's SOURCES property + cmake_policy(SET CMP0051 NEW) +endif() + +if (POLICY CMP0053) + # simplify variable reference and escape sequence evaluation + cmake_policy(SET CMP0053 NEW) +endif() + +if (POLICY CMP0054) + # only interpret if() arguments as variables or keywords when unquoted + cmake_policy(SET CMP0054 NEW) +endif() + +if (POLICY CMP0055) + # strict checking for break() command + cmake_policy(SET CMP0055 NEW) +endif() + +include(CMakeParseArguments) +include(ProcessorCount) + +function (cotire_get_configuration_types _configsVar) + set (_configs "") + if (CMAKE_CONFIGURATION_TYPES) + list (APPEND _configs ${CMAKE_CONFIGURATION_TYPES}) + endif() + if (CMAKE_BUILD_TYPE) + list (APPEND _configs "${CMAKE_BUILD_TYPE}") + endif() + if (_configs) + list (REMOVE_DUPLICATES _configs) + set (${_configsVar} ${_configs} PARENT_SCOPE) + else() + set (${_configsVar} "None" PARENT_SCOPE) + endif() +endfunction() + +function (cotire_get_source_file_extension _sourceFile _extVar) + # get_filename_component returns extension from first occurrence of . in file name + # this function computes the extension from last occurrence of . in file name + string (FIND "${_sourceFile}" "." _index REVERSE) + if (_index GREATER -1) + math (EXPR _index "${_index} + 1") + string (SUBSTRING "${_sourceFile}" ${_index} -1 _sourceExt) + else() + set (_sourceExt "") + endif() + set (${_extVar} "${_sourceExt}" PARENT_SCOPE) +endfunction() + +macro (cotire_check_is_path_relative_to _path _isRelativeVar) + set (${_isRelativeVar} FALSE) + if (IS_ABSOLUTE "${_path}") + foreach (_dir ${ARGN}) + file (RELATIVE_PATH _relPath "${_dir}" "${_path}") + if (NOT _relPath OR (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.")) + set (${_isRelativeVar} TRUE) + break() + endif() + endforeach() + endif() +endmacro() + +function (cotire_filter_language_source_files _language _target _sourceFilesVar _excludedSourceFilesVar _cotiredSourceFilesVar) + if (CMAKE_${_language}_SOURCE_FILE_EXTENSIONS) + set (_languageExtensions "${CMAKE_${_language}_SOURCE_FILE_EXTENSIONS}") + else() + set (_languageExtensions "") + endif() + if (CMAKE_${_language}_IGNORE_EXTENSIONS) + set (_ignoreExtensions "${CMAKE_${_language}_IGNORE_EXTENSIONS}") + else() + set (_ignoreExtensions "") + endif() + if (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS) + set (_excludeExtensions "${COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS}") + else() + set (_excludeExtensions "") + endif() + if (COTIRE_DEBUG AND _languageExtensions) + message (STATUS "${_language} source file extensions: ${_languageExtensions}") + endif() + if (COTIRE_DEBUG AND _ignoreExtensions) + message (STATUS "${_language} ignore extensions: ${_ignoreExtensions}") + endif() + if (COTIRE_DEBUG AND _excludeExtensions) + message (STATUS "${_language} exclude extensions: ${_excludeExtensions}") + endif() + if (CMAKE_VERSION VERSION_LESS "3.1.0") + set (_allSourceFiles ${ARGN}) + else() + # as of CMake 3.1 target sources may contain generator expressions + # since we cannot obtain required property information about source files added + # through generator expressions at configure time, we filter them out + string (GENEX_STRIP "${ARGN}" _allSourceFiles) + endif() + set (_filteredSourceFiles "") + set (_excludedSourceFiles "") + foreach (_sourceFile ${_allSourceFiles}) + get_source_file_property(_sourceIsHeaderOnly "${_sourceFile}" HEADER_FILE_ONLY) + get_source_file_property(_sourceIsExternal "${_sourceFile}" EXTERNAL_OBJECT) + get_source_file_property(_sourceIsSymbolic "${_sourceFile}" SYMBOLIC) + if (NOT _sourceIsHeaderOnly AND NOT _sourceIsExternal AND NOT _sourceIsSymbolic) + cotire_get_source_file_extension("${_sourceFile}" _sourceExt) + if (_sourceExt) + list (FIND _ignoreExtensions "${_sourceExt}" _ignoreIndex) + if (_ignoreIndex LESS 0) + list (FIND _excludeExtensions "${_sourceExt}" _excludeIndex) + if (_excludeIndex GREATER -1) + list (APPEND _excludedSourceFiles "${_sourceFile}") + else() + list (FIND _languageExtensions "${_sourceExt}" _sourceIndex) + if (_sourceIndex GREATER -1) + # consider source file unless it is excluded explicitly + get_source_file_property(_sourceIsExcluded "${_sourceFile}" COTIRE_EXCLUDED) + if (_sourceIsExcluded) + list (APPEND _excludedSourceFiles "${_sourceFile}") + else() + list (APPEND _filteredSourceFiles "${_sourceFile}") + endif() + else() + get_source_file_property(_sourceLanguage "${_sourceFile}" LANGUAGE) + if ("${_sourceLanguage}" STREQUAL "${_language}") + # add to excluded sources, if file is not ignored and has correct language without having the correct extension + list (APPEND _excludedSourceFiles "${_sourceFile}") + endif() + endif() + endif() + endif() + endif() + endif() + endforeach() + # separate filtered source files from already cotired ones + # the COTIRE_TARGET property of a source file may be set while a target is being processed by cotire + set (_sourceFiles "") + set (_cotiredSourceFiles "") + foreach (_sourceFile ${_filteredSourceFiles}) + get_source_file_property(_sourceIsCotired "${_sourceFile}" COTIRE_TARGET) + if (_sourceIsCotired) + list (APPEND _cotiredSourceFiles "${_sourceFile}") + else() + get_source_file_property(_sourceCompileFlags "${_sourceFile}" COMPILE_FLAGS) + if (_sourceCompileFlags) + # add to excluded sources, if file has custom compile flags + list (APPEND _excludedSourceFiles "${_sourceFile}") + else() + list (APPEND _sourceFiles "${_sourceFile}") + endif() + endif() + endforeach() + if (COTIRE_DEBUG) + if (_sourceFiles) + message (STATUS "Filtered ${_target} ${_language} sources: ${_sourceFiles}") + endif() + if (_excludedSourceFiles) + message (STATUS "Excluded ${_target} ${_language} sources: ${_excludedSourceFiles}") + endif() + if (_cotiredSourceFiles) + message (STATUS "Cotired ${_target} ${_language} sources: ${_cotiredSourceFiles}") + endif() + endif() + set (${_sourceFilesVar} ${_sourceFiles} PARENT_SCOPE) + set (${_excludedSourceFilesVar} ${_excludedSourceFiles} PARENT_SCOPE) + set (${_cotiredSourceFilesVar} ${_cotiredSourceFiles} PARENT_SCOPE) +endfunction() + +function (cotire_get_objects_with_property_on _filteredObjectsVar _property _type) + set (_filteredObjects "") + foreach (_object ${ARGN}) + get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET) + if (_isSet) + get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) + if (_propertyValue) + list (APPEND _filteredObjects "${_object}") + endif() + endif() + endforeach() + set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE) +endfunction() + +function (cotire_get_objects_with_property_off _filteredObjectsVar _property _type) + set (_filteredObjects "") + foreach (_object ${ARGN}) + get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET) + if (_isSet) + get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) + if (NOT _propertyValue) + list (APPEND _filteredObjects "${_object}") + endif() + endif() + endforeach() + set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_file_property_values _valuesVar _property) + set (_values "") + foreach (_sourceFile ${ARGN}) + get_source_file_property(_propertyValue "${_sourceFile}" ${_property}) + if (_propertyValue) + list (APPEND _values "${_propertyValue}") + endif() + endforeach() + set (${_valuesVar} ${_values} PARENT_SCOPE) +endfunction() + +function (cotire_resolve_config_properties _configurations _propertiesVar) + set (_properties "") + foreach (_property ${ARGN}) + if ("${_property}" MATCHES "") + foreach (_config ${_configurations}) + string (TOUPPER "${_config}" _upperConfig) + string (REPLACE "" "${_upperConfig}" _configProperty "${_property}") + list (APPEND _properties ${_configProperty}) + endforeach() + else() + list (APPEND _properties ${_property}) + endif() + endforeach() + set (${_propertiesVar} ${_properties} PARENT_SCOPE) +endfunction() + +function (cotire_copy_set_properties _configurations _type _source _target) + cotire_resolve_config_properties("${_configurations}" _properties ${ARGN}) + foreach (_property ${_properties}) + get_property(_isSet ${_type} ${_source} PROPERTY ${_property} SET) + if (_isSet) + get_property(_propertyValue ${_type} ${_source} PROPERTY ${_property}) + set_property(${_type} ${_target} PROPERTY ${_property} "${_propertyValue}") + endif() + endforeach() +endfunction() + +function (cotire_get_target_usage_requirements _target _config _targetRequirementsVar) + set (_targetRequirements "") + get_target_property(_librariesToProcess ${_target} LINK_LIBRARIES) + while (_librariesToProcess) + # remove from head + list (GET _librariesToProcess 0 _library) + list (REMOVE_AT _librariesToProcess 0) + if (_library MATCHES "^\\$<\\$:([A-Za-z0-9_:-]+)>$") + set (_library "${CMAKE_MATCH_1}") + elseif (_config STREQUAL "None" AND _library MATCHES "^\\$<\\$:([A-Za-z0-9_:-]+)>$") + set (_library "${CMAKE_MATCH_1}") + endif() + if (TARGET ${_library}) + list (FIND _targetRequirements ${_library} _index) + if (_index LESS 0) + list (APPEND _targetRequirements ${_library}) + # BFS traversal of transitive libraries + get_target_property(_libraries ${_library} INTERFACE_LINK_LIBRARIES) + if (_libraries) + list (APPEND _librariesToProcess ${_libraries}) + list (REMOVE_DUPLICATES _librariesToProcess) + endif() + endif() + endif() + endwhile() + set (${_targetRequirementsVar} ${_targetRequirements} PARENT_SCOPE) +endfunction() + +function (cotire_filter_compile_flags _language _flagFilter _matchedOptionsVar _unmatchedOptionsVar) + if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + set (_flagPrefix "[/-]") + else() + set (_flagPrefix "--?") + endif() + set (_optionFlag "") + set (_matchedOptions "") + set (_unmatchedOptions "") + foreach (_compileFlag ${ARGN}) + if (_compileFlag) + if (_optionFlag AND NOT "${_compileFlag}" MATCHES "^${_flagPrefix}") + # option with separate argument + list (APPEND _matchedOptions "${_compileFlag}") + set (_optionFlag "") + elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})$") + # remember option + set (_optionFlag "${CMAKE_MATCH_2}") + elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})(.+)$") + # option with joined argument + list (APPEND _matchedOptions "${CMAKE_MATCH_3}") + set (_optionFlag "") + else() + # flush remembered option + if (_optionFlag) + list (APPEND _matchedOptions "${_optionFlag}") + set (_optionFlag "") + endif() + # add to unfiltered options + list (APPEND _unmatchedOptions "${_compileFlag}") + endif() + endif() + endforeach() + if (_optionFlag) + list (APPEND _matchedOptions "${_optionFlag}") + endif() + if (COTIRE_DEBUG AND _matchedOptions) + message (STATUS "Filter ${_flagFilter} matched: ${_matchedOptions}") + endif() + if (COTIRE_DEBUG AND _unmatchedOptions) + message (STATUS "Filter ${_flagFilter} unmatched: ${_unmatchedOptions}") + endif() + set (${_matchedOptionsVar} ${_matchedOptions} PARENT_SCOPE) + set (${_unmatchedOptionsVar} ${_unmatchedOptions} PARENT_SCOPE) +endfunction() + +function (cotire_is_target_supported _target _isSupportedVar) + if (NOT TARGET "${_target}") + set (${_isSupportedVar} FALSE PARENT_SCOPE) + return() + endif() + get_target_property(_imported ${_target} IMPORTED) + if (_imported) + set (${_isSupportedVar} FALSE PARENT_SCOPE) + return() + endif() + get_target_property(_targetType ${_target} TYPE) + if (NOT _targetType MATCHES "EXECUTABLE|(STATIC|SHARED|MODULE|OBJECT)_LIBRARY") + set (${_isSupportedVar} FALSE PARENT_SCOPE) + return() + endif() + set (${_isSupportedVar} TRUE PARENT_SCOPE) +endfunction() + +function (cotire_get_target_compile_flags _config _language _target _flagsVar) + string (TOUPPER "${_config}" _upperConfig) + # collect options from CMake language variables + set (_compileFlags "") + if (CMAKE_${_language}_FLAGS) + set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS}") + endif() + if (CMAKE_${_language}_FLAGS_${_upperConfig}) + set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS_${_upperConfig}}") + endif() + if (_target) + # add target compile flags + get_target_property(_targetflags ${_target} COMPILE_FLAGS) + if (_targetflags) + set (_compileFlags "${_compileFlags} ${_targetflags}") + endif() + endif() + if (UNIX) + separate_arguments(_compileFlags UNIX_COMMAND "${_compileFlags}") + elseif(WIN32) + separate_arguments(_compileFlags WINDOWS_COMMAND "${_compileFlags}") + else() + separate_arguments(_compileFlags) + endif() + # target compile options + if (_target) + get_target_property(_targetOptions ${_target} COMPILE_OPTIONS) + if (_targetOptions) + list (APPEND _compileFlags ${_targetOptions}) + endif() + endif() + # interface compile options from linked library targets + if (_target) + set (_linkedTargets "") + cotire_get_target_usage_requirements(${_target} ${_config} _linkedTargets) + foreach (_linkedTarget ${_linkedTargets}) + get_target_property(_targetOptions ${_linkedTarget} INTERFACE_COMPILE_OPTIONS) + if (_targetOptions) + list (APPEND _compileFlags ${_targetOptions}) + endif() + endforeach() + endif() + # handle language standard properties + if (CMAKE_${_language}_STANDARD_DEFAULT) + # used compiler supports language standard levels + if (_target) + get_target_property(_targetLanguageStandard ${_target} ${_language}_STANDARD) + if (_targetLanguageStandard) + set (_type "EXTENSION") + get_property(_isSet TARGET ${_target} PROPERTY ${_language}_EXTENSIONS SET) + if (_isSet) + get_target_property(_targetUseLanguageExtensions ${_target} ${_language}_EXTENSIONS) + if (NOT _targetUseLanguageExtensions) + set (_type "STANDARD") + endif() + endif() + if (CMAKE_${_language}${_targetLanguageStandard}_${_type}_COMPILE_OPTION) + list (APPEND _compileFlags "${CMAKE_${_language}${_targetLanguageStandard}_${_type}_COMPILE_OPTION}") + endif() + endif() + endif() + endif() + # handle the POSITION_INDEPENDENT_CODE target property + if (_target) + get_target_property(_targetPIC ${_target} POSITION_INDEPENDENT_CODE) + if (_targetPIC) + get_target_property(_targetType ${_target} TYPE) + if (_targetType STREQUAL "EXECUTABLE" AND CMAKE_${_language}_COMPILE_OPTIONS_PIE) + list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_PIE}") + elseif (CMAKE_${_language}_COMPILE_OPTIONS_PIC) + list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_PIC}") + endif() + endif() + endif() + # handle visibility target properties + if (_target) + get_target_property(_targetVisibility ${_target} ${_language}_VISIBILITY_PRESET) + if (_targetVisibility AND CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY) + list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY}${_targetVisibility}") + endif() + get_target_property(_targetVisibilityInlines ${_target} VISIBILITY_INLINES_HIDDEN) + if (_targetVisibilityInlines AND CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN) + list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN}") + endif() + endif() + # platform specific flags + if (APPLE) + get_target_property(_architectures ${_target} OSX_ARCHITECTURES_${_upperConfig}) + if (NOT _architectures) + get_target_property(_architectures ${_target} OSX_ARCHITECTURES) + endif() + if (_architectures) + foreach (_arch ${_architectures}) + list (APPEND _compileFlags "-arch" "${_arch}") + endforeach() + endif() + if (CMAKE_OSX_SYSROOT) + if (CMAKE_${_language}_SYSROOT_FLAG) + list (APPEND _compileFlags "${CMAKE_${_language}_SYSROOT_FLAG}" "${CMAKE_OSX_SYSROOT}") + else() + list (APPEND _compileFlags "-isysroot" "${CMAKE_OSX_SYSROOT}") + endif() + endif() + if (CMAKE_OSX_DEPLOYMENT_TARGET) + if (CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG) + list (APPEND _compileFlags "${CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}") + else() + list (APPEND _compileFlags "-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") + endif() + endif() + endif() + if (COTIRE_DEBUG AND _compileFlags) + message (STATUS "Target ${_target} compile flags: ${_compileFlags}") + endif() + set (${_flagsVar} ${_compileFlags} PARENT_SCOPE) +endfunction() + +function (cotire_get_target_include_directories _config _language _target _includeDirsVar _systemIncludeDirsVar) + set (_includeDirs "") + set (_systemIncludeDirs "") + # default include dirs + if (CMAKE_INCLUDE_CURRENT_DIR) + list (APPEND _includeDirs "${CMAKE_CURRENT_BINARY_DIR}") + list (APPEND _includeDirs "${CMAKE_CURRENT_SOURCE_DIR}") + endif() + set (_targetFlags "") + cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) + # parse additional include directories from target compile flags + if (CMAKE_INCLUDE_FLAG_${_language}) + string (STRIP "${CMAKE_INCLUDE_FLAG_${_language}}" _includeFlag) + string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") + if (_includeFlag) + set (_dirs "") + cotire_filter_compile_flags("${_language}" "${_includeFlag}" _dirs _ignore ${_targetFlags}) + if (_dirs) + list (APPEND _includeDirs ${_dirs}) + endif() + endif() + endif() + # parse additional system include directories from target compile flags + if (CMAKE_INCLUDE_SYSTEM_FLAG_${_language}) + string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" _includeFlag) + string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") + if (_includeFlag) + set (_dirs "") + cotire_filter_compile_flags("${_language}" "${_includeFlag}" _dirs _ignore ${_targetFlags}) + if (_dirs) + list (APPEND _systemIncludeDirs ${_dirs}) + endif() + endif() + endif() + # target include directories + get_directory_property(_dirs DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" INCLUDE_DIRECTORIES) + if (_target) + get_target_property(_targetDirs ${_target} INCLUDE_DIRECTORIES) + if (_targetDirs) + list (APPEND _dirs ${_targetDirs}) + endif() + get_target_property(_targetDirs ${_target} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) + if (_targetDirs) + list (APPEND _systemIncludeDirs ${_targetDirs}) + endif() + endif() + # interface include directories from linked library targets + if (_target) + set (_linkedTargets "") + cotire_get_target_usage_requirements(${_target} ${_config} _linkedTargets) + foreach (_linkedTarget ${_linkedTargets}) + get_target_property(_linkedTargetType ${_linkedTarget} TYPE) + if (CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE AND NOT CMAKE_VERSION VERSION_LESS "3.4.0" AND + _linkedTargetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY") + # CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE refers to CMAKE_CURRENT_BINARY_DIR and CMAKE_CURRENT_SOURCE_DIR + # at the time, when the target was created. These correspond to the target properties BINARY_DIR and SOURCE_DIR + # which are only available with CMake 3.4 or later. + get_target_property(_targetDirs ${_linkedTarget} BINARY_DIR) + if (_targetDirs) + list (APPEND _dirs ${_targetDirs}) + endif() + get_target_property(_targetDirs ${_linkedTarget} SOURCE_DIR) + if (_targetDirs) + list (APPEND _dirs ${_targetDirs}) + endif() + endif() + get_target_property(_targetDirs ${_linkedTarget} INTERFACE_INCLUDE_DIRECTORIES) + if (_targetDirs) + list (APPEND _dirs ${_targetDirs}) + endif() + get_target_property(_targetDirs ${_linkedTarget} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) + if (_targetDirs) + list (APPEND _systemIncludeDirs ${_targetDirs}) + endif() + endforeach() + endif() + if (dirs) + list (REMOVE_DUPLICATES _dirs) + endif() + list (LENGTH _includeDirs _projectInsertIndex) + foreach (_dir ${_dirs}) + if (CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE) + cotire_check_is_path_relative_to("${_dir}" _isRelative "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}") + if (_isRelative) + list (LENGTH _includeDirs _len) + if (_len EQUAL _projectInsertIndex) + list (APPEND _includeDirs "${_dir}") + else() + list (INSERT _includeDirs _projectInsertIndex "${_dir}") + endif() + math (EXPR _projectInsertIndex "${_projectInsertIndex} + 1") + else() + list (APPEND _includeDirs "${_dir}") + endif() + else() + list (APPEND _includeDirs "${_dir}") + endif() + endforeach() + list (REMOVE_DUPLICATES _includeDirs) + list (REMOVE_DUPLICATES _systemIncludeDirs) + if (CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES) + list (REMOVE_ITEM _includeDirs ${CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES}) + endif() + if (WIN32 AND NOT MINGW) + # convert Windows paths in include directories to CMake paths + if (_includeDirs) + set (_paths "") + foreach (_dir ${_includeDirs}) + file (TO_CMAKE_PATH "${_dir}" _path) + list (APPEND _paths "${_path}") + endforeach() + set (_includeDirs ${_paths}) + endif() + if (_systemIncludeDirs) + set (_paths "") + foreach (_dir ${_systemIncludeDirs}) + file (TO_CMAKE_PATH "${_dir}" _path) + list (APPEND _paths "${_path}") + endforeach() + set (_systemIncludeDirs ${_paths}) + endif() + endif() + if (COTIRE_DEBUG AND _includeDirs) + message (STATUS "Target ${_target} include dirs: ${_includeDirs}") + endif() + set (${_includeDirsVar} ${_includeDirs} PARENT_SCOPE) + if (COTIRE_DEBUG AND _systemIncludeDirs) + message (STATUS "Target ${_target} system include dirs: ${_systemIncludeDirs}") + endif() + set (${_systemIncludeDirsVar} ${_systemIncludeDirs} PARENT_SCOPE) +endfunction() + +function (cotire_get_target_export_symbol _target _exportSymbolVar) + set (_exportSymbol "") + get_target_property(_targetType ${_target} TYPE) + get_target_property(_enableExports ${_target} ENABLE_EXPORTS) + if (_targetType MATCHES "(SHARED|MODULE)_LIBRARY" OR + (_targetType STREQUAL "EXECUTABLE" AND _enableExports)) + get_target_property(_exportSymbol ${_target} DEFINE_SYMBOL) + if (NOT _exportSymbol) + set (_exportSymbol "${_target}_EXPORTS") + endif() + string (MAKE_C_IDENTIFIER "${_exportSymbol}" _exportSymbol) + endif() + set (${_exportSymbolVar} ${_exportSymbol} PARENT_SCOPE) +endfunction() + +function (cotire_get_target_compile_definitions _config _language _target _definitionsVar) + string (TOUPPER "${_config}" _upperConfig) + set (_configDefinitions "") + # CMAKE_INTDIR for multi-configuration build systems + if (NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".") + list (APPEND _configDefinitions "CMAKE_INTDIR=\"${_config}\"") + endif() + # target export define symbol + cotire_get_target_export_symbol("${_target}" _defineSymbol) + if (_defineSymbol) + list (APPEND _configDefinitions "${_defineSymbol}") + endif() + # directory compile definitions + get_directory_property(_definitions DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + get_directory_property(_definitions DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS_${_upperConfig}) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + # target compile definitions + get_target_property(_definitions ${_target} COMPILE_DEFINITIONS) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + get_target_property(_definitions ${_target} COMPILE_DEFINITIONS_${_upperConfig}) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + # interface compile definitions from linked library targets + set (_linkedTargets "") + cotire_get_target_usage_requirements(${_target} ${_config} _linkedTargets) + foreach (_linkedTarget ${_linkedTargets}) + get_target_property(_definitions ${_linkedTarget} INTERFACE_COMPILE_DEFINITIONS) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + endforeach() + # parse additional compile definitions from target compile flags + # and don't look at directory compile definitions, which we already handled + set (_targetFlags "") + cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) + cotire_filter_compile_flags("${_language}" "D" _definitions _ignore ${_targetFlags}) + if (_definitions) + list (APPEND _configDefinitions ${_definitions}) + endif() + list (REMOVE_DUPLICATES _configDefinitions) + if (COTIRE_DEBUG AND _configDefinitions) + message (STATUS "Target ${_target} compile definitions: ${_configDefinitions}") + endif() + set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE) +endfunction() + +function (cotire_get_target_compiler_flags _config _language _target _compilerFlagsVar) + # parse target compile flags omitting compile definitions and include directives + set (_targetFlags "") + cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) + set (_flagFilter "D") + if (CMAKE_INCLUDE_FLAG_${_language}) + string (STRIP "${CMAKE_INCLUDE_FLAG_${_language}}" _includeFlag) + string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") + if (_includeFlag) + set (_flagFilter "${_flagFilter}|${_includeFlag}") + endif() + endif() + if (CMAKE_INCLUDE_SYSTEM_FLAG_${_language}) + string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" _includeFlag) + string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") + if (_includeFlag) + set (_flagFilter "${_flagFilter}|${_includeFlag}") + endif() + endif() + set (_compilerFlags "") + cotire_filter_compile_flags("${_language}" "${_flagFilter}" _ignore _compilerFlags ${_targetFlags}) + if (COTIRE_DEBUG AND _compilerFlags) + message (STATUS "Target ${_target} compiler flags: ${_compilerFlags}") + endif() + set (${_compilerFlagsVar} ${_compilerFlags} PARENT_SCOPE) +endfunction() + +function (cotire_add_sys_root_paths _pathsVar) + if (APPLE) + if (CMAKE_OSX_SYSROOT AND CMAKE_${_language}_HAS_ISYSROOT) + foreach (_path IN LISTS ${_pathsVar}) + if (IS_ABSOLUTE "${_path}") + get_filename_component(_path "${CMAKE_OSX_SYSROOT}/${_path}" ABSOLUTE) + if (EXISTS "${_path}") + list (APPEND ${_pathsVar} "${_path}") + endif() + endif() + endforeach() + endif() + endif() + set (${_pathsVar} ${${_pathsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_extra_properties _sourceFile _pattern _resultVar) + set (_extraProperties ${ARGN}) + set (_result "") + if (_extraProperties) + list (FIND _extraProperties "${_sourceFile}" _index) + if (_index GREATER -1) + math (EXPR _index "${_index} + 1") + list (LENGTH _extraProperties _len) + math (EXPR _len "${_len} - 1") + foreach (_index RANGE ${_index} ${_len}) + list (GET _extraProperties ${_index} _value) + if (_value MATCHES "${_pattern}") + list (APPEND _result "${_value}") + else() + break() + endif() + endforeach() + endif() + endif() + set (${_resultVar} ${_result} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_compile_definitions _config _language _sourceFile _definitionsVar) + set (_compileDefinitions "") + if (NOT CMAKE_SCRIPT_MODE_FILE) + string (TOUPPER "${_config}" _upperConfig) + get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS) + if (_definitions) + list (APPEND _compileDefinitions ${_definitions}) + endif() + get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS_${_upperConfig}) + if (_definitions) + list (APPEND _compileDefinitions ${_definitions}) + endif() + endif() + cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+(=.*)?$" _definitions ${ARGN}) + if (_definitions) + list (APPEND _compileDefinitions ${_definitions}) + endif() + if (COTIRE_DEBUG AND _compileDefinitions) + message (STATUS "Source ${_sourceFile} compile definitions: ${_compileDefinitions}") + endif() + set (${_definitionsVar} ${_compileDefinitions} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_files_compile_definitions _config _language _definitionsVar) + set (_configDefinitions "") + foreach (_sourceFile ${ARGN}) + cotire_get_source_compile_definitions("${_config}" "${_language}" "${_sourceFile}" _sourceDefinitions) + if (_sourceDefinitions) + list (APPEND _configDefinitions "${_sourceFile}" ${_sourceDefinitions} "-") + endif() + endforeach() + set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_undefs _sourceFile _property _sourceUndefsVar) + set (_sourceUndefs "") + if (NOT CMAKE_SCRIPT_MODE_FILE) + get_source_file_property(_undefs "${_sourceFile}" ${_property}) + if (_undefs) + list (APPEND _sourceUndefs ${_undefs}) + endif() + endif() + cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+$" _undefs ${ARGN}) + if (_undefs) + list (APPEND _sourceUndefs ${_undefs}) + endif() + if (COTIRE_DEBUG AND _sourceUndefs) + message (STATUS "Source ${_sourceFile} ${_property} undefs: ${_sourceUndefs}") + endif() + set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE) +endfunction() + +function (cotire_get_source_files_undefs _property _sourceUndefsVar) + set (_sourceUndefs "") + foreach (_sourceFile ${ARGN}) + cotire_get_source_undefs("${_sourceFile}" ${_property} _undefs) + if (_undefs) + list (APPEND _sourceUndefs "${_sourceFile}" ${_undefs} "-") + endif() + endforeach() + set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE) +endfunction() + +macro (cotire_set_cmd_to_prologue _cmdVar) + set (${_cmdVar} "${CMAKE_COMMAND}") + if (COTIRE_DEBUG) + list (APPEND ${_cmdVar} "--warn-uninitialized") + endif() + list (APPEND ${_cmdVar} "-DCOTIRE_BUILD_TYPE:STRING=$") + if (XCODE) + list (APPEND ${_cmdVar} "-DXCODE:BOOL=TRUE") + endif() + if (COTIRE_VERBOSE) + list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=ON") + elseif("${CMAKE_GENERATOR}" MATCHES "Makefiles") + list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=$(VERBOSE)") + endif() +endmacro() + +function (cotire_init_compile_cmd _cmdVar _language _compilerLauncher _compilerExe _compilerArg1) + if (NOT _compilerLauncher) + set (_compilerLauncher ${CMAKE_${_language}_COMPILER_LAUNCHER}) + endif() + if (NOT _compilerExe) + set (_compilerExe "${CMAKE_${_language}_COMPILER}") + endif() + if (NOT _compilerArg1) + set (_compilerArg1 ${CMAKE_${_language}_COMPILER_ARG1}) + endif() + string (STRIP "${_compilerArg1}" _compilerArg1) + if ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") + # compiler launcher is only supported for Makefile and Ninja + set (${_cmdVar} ${_compilerLauncher} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE) + else() + set (${_cmdVar} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE) + endif() +endfunction() + +macro (cotire_add_definitions_to_cmd _cmdVar _language) + foreach (_definition ${ARGN}) + if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + list (APPEND ${_cmdVar} "/D${_definition}") + else() + list (APPEND ${_cmdVar} "-D${_definition}") + endif() + endforeach() +endmacro() + +function (cotire_add_includes_to_cmd _cmdVar _language _includesVar _systemIncludesVar) + set (_includeDirs ${${_includesVar}} ${${_systemIncludesVar}}) + if (_includeDirs) + list (REMOVE_DUPLICATES _includeDirs) + foreach (_include ${_includeDirs}) + if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + file (TO_NATIVE_PATH "${_include}" _include) + list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_SEP_${_language}}${_include}") + else() + set (_index -1) + if ("${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" MATCHES ".+") + list (FIND ${_systemIncludesVar} "${_include}" _index) + endif() + if (_index GREATER -1) + list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_SEP_${_language}}${_include}") + else() + list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_SEP_${_language}}${_include}") + endif() + endif() + endforeach() + endif() + set (${_cmdVar} ${${_cmdVar}} PARENT_SCOPE) +endfunction() + +function (cotire_add_frameworks_to_cmd _cmdVar _language _includesVar _systemIncludesVar) + if (APPLE) + set (_frameworkDirs "") + foreach (_include ${${_includesVar}}) + if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$") + get_filename_component(_frameworkDir "${_include}" DIRECTORY) + list (APPEND _frameworkDirs "${_frameworkDir}") + endif() + endforeach() + set (_systemFrameworkDirs "") + foreach (_include ${${_systemIncludesVar}}) + if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$") + get_filename_component(_frameworkDir "${_include}" DIRECTORY) + list (APPEND _systemFrameworkDirs "${_frameworkDir}") + endif() + endforeach() + if (_systemFrameworkDirs) + list (APPEND _frameworkDirs ${_systemFrameworkDirs}) + endif() + if (_frameworkDirs) + list (REMOVE_DUPLICATES _frameworkDirs) + foreach (_frameworkDir ${_frameworkDirs}) + set (_index -1) + if ("${CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG}" MATCHES ".+") + list (FIND _systemFrameworkDirs "${_frameworkDir}" _index) + endif() + if (_index GREATER -1) + list (APPEND ${_cmdVar} "${CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG}${_frameworkDir}") + else() + list (APPEND ${_cmdVar} "${CMAKE_${_language}_FRAMEWORK_SEARCH_FLAG}${_frameworkDir}") + endif() + endforeach() + endif() + endif() + set (${_cmdVar} ${${_cmdVar}} PARENT_SCOPE) +endfunction() + +macro (cotire_add_compile_flags_to_cmd _cmdVar) + foreach (_flag ${ARGN}) + list (APPEND ${_cmdVar} "${_flag}") + endforeach() +endmacro() + +function (cotire_check_file_up_to_date _fileIsUpToDateVar _file) + if (EXISTS "${_file}") + set (_triggerFile "") + foreach (_dependencyFile ${ARGN}) + if (EXISTS "${_dependencyFile}") + # IS_NEWER_THAN returns TRUE if both files have the same timestamp + # thus we do the comparison in both directions to exclude ties + if ("${_dependencyFile}" IS_NEWER_THAN "${_file}" AND + NOT "${_file}" IS_NEWER_THAN "${_dependencyFile}") + set (_triggerFile "${_dependencyFile}") + break() + endif() + endif() + endforeach() + if (_triggerFile) + if (COTIRE_VERBOSE) + get_filename_component(_fileName "${_file}" NAME) + message (STATUS "${_fileName} update triggered by ${_triggerFile} change.") + endif() + set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE) + else() + if (COTIRE_VERBOSE) + get_filename_component(_fileName "${_file}" NAME) + message (STATUS "${_fileName} is up-to-date.") + endif() + set (${_fileIsUpToDateVar} TRUE PARENT_SCOPE) + endif() + else() + if (COTIRE_VERBOSE) + get_filename_component(_fileName "${_file}" NAME) + message (STATUS "${_fileName} does not exist yet.") + endif() + set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE) + endif() +endfunction() + +macro (cotire_find_closest_relative_path _headerFile _includeDirs _relPathVar) + set (${_relPathVar} "") + foreach (_includeDir ${_includeDirs}) + if (IS_DIRECTORY "${_includeDir}") + file (RELATIVE_PATH _relPath "${_includeDir}" "${_headerFile}") + if (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.") + string (LENGTH "${${_relPathVar}}" _closestLen) + string (LENGTH "${_relPath}" _relLen) + if (_closestLen EQUAL 0 OR _relLen LESS _closestLen) + set (${_relPathVar} "${_relPath}") + endif() + endif() + elseif ("${_includeDir}" STREQUAL "${_headerFile}") + # if path matches exactly, return short non-empty string + set (${_relPathVar} "1") + break() + endif() + endforeach() +endmacro() + +macro (cotire_check_header_file_location _headerFile _insideIncludeDirs _outsideIncludeDirs _headerIsInside) + # check header path against ignored and honored include directories + cotire_find_closest_relative_path("${_headerFile}" "${_insideIncludeDirs}" _insideRelPath) + if (_insideRelPath) + # header is inside, but could be become outside if there is a shorter outside match + cotire_find_closest_relative_path("${_headerFile}" "${_outsideIncludeDirs}" _outsideRelPath) + if (_outsideRelPath) + string (LENGTH "${_insideRelPath}" _insideRelPathLen) + string (LENGTH "${_outsideRelPath}" _outsideRelPathLen) + if (_outsideRelPathLen LESS _insideRelPathLen) + set (${_headerIsInside} FALSE) + else() + set (${_headerIsInside} TRUE) + endif() + else() + set (${_headerIsInside} TRUE) + endif() + else() + # header is outside + set (${_headerIsInside} FALSE) + endif() +endmacro() + +macro (cotire_check_ignore_header_file_path _headerFile _headerIsIgnoredVar) + if (NOT EXISTS "${_headerFile}") + set (${_headerIsIgnoredVar} TRUE) + elseif (IS_DIRECTORY "${_headerFile}") + set (${_headerIsIgnoredVar} TRUE) + elseif ("${_headerFile}" MATCHES "\\.\\.|[_-]fixed" AND "${_headerFile}" MATCHES "\\.h$") + # heuristic: ignore C headers with embedded parent directory references or "-fixed" or "_fixed" in path + # these often stem from using GCC #include_next tricks, which may break the precompiled header compilation + # with the error message "error: no include path in which to search for header.h" + set (${_headerIsIgnoredVar} TRUE) + else() + set (${_headerIsIgnoredVar} FALSE) + endif() +endmacro() + +macro (cotire_check_ignore_header_file_ext _headerFile _ignoreExtensionsVar _headerIsIgnoredVar) + # check header file extension + cotire_get_source_file_extension("${_headerFile}" _headerFileExt) + set (${_headerIsIgnoredVar} FALSE) + if (_headerFileExt) + list (FIND ${_ignoreExtensionsVar} "${_headerFileExt}" _index) + if (_index GREATER -1) + set (${_headerIsIgnoredVar} TRUE) + endif() + endif() +endmacro() + +macro (cotire_parse_line _line _headerFileVar _headerDepthVar) + if (MSVC) + # cl.exe /showIncludes output looks different depending on the language pack used, e.g.: + # English: "Note: including file: C:\directory\file" + # German: "Hinweis: Einlesen der Datei: C:\directory\file" + # We use a very general regular expression, relying on the presence of the : characters + if (_line MATCHES "( +)([a-zA-Z]:[^:]+)$") + # Visual Studio compiler output + string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar}) + get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" ABSOLUTE) + else() + set (${_headerFileVar} "") + set (${_headerDepthVar} 0) + endif() + else() + if (_line MATCHES "^(\\.+) (.*)$") + # GCC like output + string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar}) + if (IS_ABSOLUTE "${CMAKE_MATCH_2}") + set (${_headerFileVar} "${CMAKE_MATCH_2}") + else() + get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" REALPATH) + endif() + else() + set (${_headerFileVar} "") + set (${_headerDepthVar} 0) + endif() + endif() +endmacro() + +function (cotire_parse_includes _language _scanOutput _ignoredIncludeDirs _honoredIncludeDirs _ignoredExtensions _selectedIncludesVar _unparsedLinesVar) + if (WIN32) + # prevent CMake macro invocation errors due to backslash characters in Windows paths + string (REPLACE "\\" "/" _scanOutput "${_scanOutput}") + endif() + # canonize slashes + string (REPLACE "//" "/" _scanOutput "${_scanOutput}") + # prevent semicolon from being interpreted as a line separator + string (REPLACE ";" "\\;" _scanOutput "${_scanOutput}") + # then separate lines + string (REGEX REPLACE "\n" ";" _scanOutput "${_scanOutput}") + list (LENGTH _scanOutput _len) + # remove duplicate lines to speed up parsing + list (REMOVE_DUPLICATES _scanOutput) + list (LENGTH _scanOutput _uniqueLen) + if (COTIRE_VERBOSE OR COTIRE_DEBUG) + message (STATUS "Scanning ${_uniqueLen} unique lines of ${_len} for includes") + if (_ignoredExtensions) + message (STATUS "Ignored extensions: ${_ignoredExtensions}") + endif() + if (_ignoredIncludeDirs) + message (STATUS "Ignored paths: ${_ignoredIncludeDirs}") + endif() + if (_honoredIncludeDirs) + message (STATUS "Included paths: ${_honoredIncludeDirs}") + endif() + endif() + set (_sourceFiles ${ARGN}) + set (_selectedIncludes "") + set (_unparsedLines "") + # stack keeps track of inside/outside project status of processed header files + set (_headerIsInsideStack "") + foreach (_line IN LISTS _scanOutput) + if (_line) + cotire_parse_line("${_line}" _headerFile _headerDepth) + if (_headerFile) + cotire_check_header_file_location("${_headerFile}" "${_ignoredIncludeDirs}" "${_honoredIncludeDirs}" _headerIsInside) + if (COTIRE_DEBUG) + message (STATUS "${_headerDepth}: ${_headerFile} ${_headerIsInside}") + endif() + # update stack + list (LENGTH _headerIsInsideStack _stackLen) + if (_headerDepth GREATER _stackLen) + math (EXPR _stackLen "${_stackLen} + 1") + foreach (_index RANGE ${_stackLen} ${_headerDepth}) + list (APPEND _headerIsInsideStack ${_headerIsInside}) + endforeach() + else() + foreach (_index RANGE ${_headerDepth} ${_stackLen}) + list (REMOVE_AT _headerIsInsideStack -1) + endforeach() + list (APPEND _headerIsInsideStack ${_headerIsInside}) + endif() + if (COTIRE_DEBUG) + message (STATUS "${_headerIsInsideStack}") + endif() + # header is a candidate if it is outside project + if (NOT _headerIsInside) + # get parent header file's inside/outside status + if (_headerDepth GREATER 1) + math (EXPR _index "${_headerDepth} - 2") + list (GET _headerIsInsideStack ${_index} _parentHeaderIsInside) + else() + set (_parentHeaderIsInside TRUE) + endif() + # select header file if parent header file is inside project + # (e.g., a project header file that includes a standard header file) + if (_parentHeaderIsInside) + cotire_check_ignore_header_file_path("${_headerFile}" _headerIsIgnored) + if (NOT _headerIsIgnored) + cotire_check_ignore_header_file_ext("${_headerFile}" _ignoredExtensions _headerIsIgnored) + if (NOT _headerIsIgnored) + list (APPEND _selectedIncludes "${_headerFile}") + else() + # fix header's inside status on stack, it is ignored by extension now + list (REMOVE_AT _headerIsInsideStack -1) + list (APPEND _headerIsInsideStack TRUE) + endif() + endif() + if (COTIRE_DEBUG) + message (STATUS "${_headerFile} ${_ignoredExtensions} ${_headerIsIgnored}") + endif() + endif() + endif() + else() + if (MSVC) + # for cl.exe do not keep unparsed lines which solely consist of a source file name + string (FIND "${_sourceFiles}" "${_line}" _index) + if (_index LESS 0) + list (APPEND _unparsedLines "${_line}") + endif() + else() + list (APPEND _unparsedLines "${_line}") + endif() + endif() + endif() + endforeach() + list (REMOVE_DUPLICATES _selectedIncludes) + set (${_selectedIncludesVar} ${_selectedIncludes} PARENT_SCOPE) + set (${_unparsedLinesVar} ${_unparsedLines} PARENT_SCOPE) +endfunction() + +function (cotire_scan_includes _includesVar) + set(_options "") + set(_oneValueArgs COMPILER_ID COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_VERSION LANGUAGE UNPARSED_LINES SCAN_RESULT) + set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES + IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS INCLUDE_PRIORITY_PATH COMPILER_LAUNCHER) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) + if (NOT _option_LANGUAGE) + set (_option_LANGUAGE "CXX") + endif() + if (NOT _option_COMPILER_ID) + set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") + endif() + if (NOT _option_COMPILER_VERSION) + set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}") + endif() + cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_LAUNCHER}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}") + cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS}) + cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS}) + cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) + cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) + cotire_add_makedep_flags("${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" _cmd) + # only consider existing source files for scanning + set (_existingSourceFiles "") + foreach (_sourceFile ${_sourceFiles}) + if (EXISTS "${_sourceFile}") + list (APPEND _existingSourceFiles "${_sourceFile}") + endif() + endforeach() + if (NOT _existingSourceFiles) + set (${_includesVar} "" PARENT_SCOPE) + return() + endif() + list (APPEND _cmd ${_existingSourceFiles}) + if (COTIRE_VERBOSE) + message (STATUS "execute_process: ${_cmd}") + endif() + if (_option_COMPILER_ID MATCHES "MSVC") + # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared + unset (ENV{VS_UNICODE_OUTPUT}) + endif() + execute_process( + COMMAND ${_cmd} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE _result + OUTPUT_QUIET + ERROR_VARIABLE _output) + if (_result) + message (STATUS "Result ${_result} scanning includes of ${_existingSourceFiles}.") + endif() + cotire_parse_includes( + "${_option_LANGUAGE}" "${_output}" + "${_option_IGNORE_PATH}" "${_option_INCLUDE_PATH}" + "${_option_IGNORE_EXTENSIONS}" + _includes _unparsedLines + ${_sourceFiles}) + if (_option_INCLUDE_PRIORITY_PATH) + set (_sortedIncludes "") + foreach (_priorityPath ${_option_INCLUDE_PRIORITY_PATH}) + foreach (_include ${_includes}) + string (FIND ${_include} ${_priorityPath} _position) + if (_position GREATER -1) + list (APPEND _sortedIncludes ${_include}) + endif() + endforeach() + endforeach() + if (_sortedIncludes) + list (INSERT _includes 0 ${_sortedIncludes}) + list (REMOVE_DUPLICATES _includes) + endif() + endif() + set (${_includesVar} ${_includes} PARENT_SCOPE) + if (_option_UNPARSED_LINES) + set (${_option_UNPARSED_LINES} ${_unparsedLines} PARENT_SCOPE) + endif() + if (_option_SCAN_RESULT) + set (${_option_SCAN_RESULT} ${_result} PARENT_SCOPE) + endif() +endfunction() + +macro (cotire_append_undefs _contentsVar) + set (_undefs ${ARGN}) + if (_undefs) + list (REMOVE_DUPLICATES _undefs) + foreach (_definition ${_undefs}) + list (APPEND ${_contentsVar} "#undef ${_definition}") + endforeach() + endif() +endmacro() + +macro (cotire_comment_str _language _commentText _commentVar) + if ("${_language}" STREQUAL "CMAKE") + set (${_commentVar} "# ${_commentText}") + else() + set (${_commentVar} "/* ${_commentText} */") + endif() +endmacro() + +function (cotire_write_file _language _file _contents _force) + get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME) + cotire_comment_str("${_language}" "${_moduleName} ${COTIRE_CMAKE_MODULE_VERSION} generated file" _header1) + cotire_comment_str("${_language}" "${_file}" _header2) + set (_contents "${_header1}\n${_header2}\n${_contents}") + if (COTIRE_DEBUG) + message (STATUS "${_contents}") + endif() + if (_force OR NOT EXISTS "${_file}") + file (WRITE "${_file}" "${_contents}") + else() + file (READ "${_file}" _oldContents) + if (NOT "${_oldContents}" STREQUAL "${_contents}") + file (WRITE "${_file}" "${_contents}") + else() + if (COTIRE_DEBUG) + message (STATUS "${_file} unchanged") + endif() + endif() + endif() +endfunction() + +function (cotire_generate_unity_source _unityFile) + set(_options "") + set(_oneValueArgs LANGUAGE) + set(_multiValueArgs + DEPENDS SOURCES_COMPILE_DEFINITIONS + PRE_UNDEFS SOURCES_PRE_UNDEFS POST_UNDEFS SOURCES_POST_UNDEFS PROLOGUE EPILOGUE) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if (_option_DEPENDS) + cotire_check_file_up_to_date(_unityFileIsUpToDate "${_unityFile}" ${_option_DEPENDS}) + if (_unityFileIsUpToDate) + return() + endif() + endif() + set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) + if (NOT _option_PRE_UNDEFS) + set (_option_PRE_UNDEFS "") + endif() + if (NOT _option_SOURCES_PRE_UNDEFS) + set (_option_SOURCES_PRE_UNDEFS "") + endif() + if (NOT _option_POST_UNDEFS) + set (_option_POST_UNDEFS "") + endif() + if (NOT _option_SOURCES_POST_UNDEFS) + set (_option_SOURCES_POST_UNDEFS "") + endif() + set (_contents "") + if (_option_PROLOGUE) + list (APPEND _contents ${_option_PROLOGUE}) + endif() + if (_option_LANGUAGE AND _sourceFiles) + if ("${_option_LANGUAGE}" STREQUAL "CXX") + list (APPEND _contents "#ifdef __cplusplus") + elseif ("${_option_LANGUAGE}" STREQUAL "C") + list (APPEND _contents "#ifndef __cplusplus") + endif() + endif() + set (_compileUndefinitions "") + foreach (_sourceFile ${_sourceFiles}) + cotire_get_source_compile_definitions( + "${_option_CONFIGURATION}" "${_option_LANGUAGE}" "${_sourceFile}" _compileDefinitions + ${_option_SOURCES_COMPILE_DEFINITIONS}) + cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_PRE_UNDEFS _sourcePreUndefs ${_option_SOURCES_PRE_UNDEFS}) + cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_POST_UNDEFS _sourcePostUndefs ${_option_SOURCES_POST_UNDEFS}) + if (_option_PRE_UNDEFS) + list (APPEND _compileUndefinitions ${_option_PRE_UNDEFS}) + endif() + if (_sourcePreUndefs) + list (APPEND _compileUndefinitions ${_sourcePreUndefs}) + endif() + if (_compileUndefinitions) + cotire_append_undefs(_contents ${_compileUndefinitions}) + set (_compileUndefinitions "") + endif() + if (_sourcePostUndefs) + list (APPEND _compileUndefinitions ${_sourcePostUndefs}) + endif() + if (_option_POST_UNDEFS) + list (APPEND _compileUndefinitions ${_option_POST_UNDEFS}) + endif() + foreach (_definition ${_compileDefinitions}) + if (_definition MATCHES "^([a-zA-Z0-9_]+)=(.+)$") + list (APPEND _contents "#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}") + list (INSERT _compileUndefinitions 0 "${CMAKE_MATCH_1}") + else() + list (APPEND _contents "#define ${_definition}") + list (INSERT _compileUndefinitions 0 "${_definition}") + endif() + endforeach() + # use absolute path as source file location + get_filename_component(_sourceFileLocation "${_sourceFile}" ABSOLUTE) + if (WIN32) + file (TO_NATIVE_PATH "${_sourceFileLocation}" _sourceFileLocation) + endif() + list (APPEND _contents "#include \"${_sourceFileLocation}\"") + endforeach() + if (_compileUndefinitions) + cotire_append_undefs(_contents ${_compileUndefinitions}) + set (_compileUndefinitions "") + endif() + if (_option_LANGUAGE AND _sourceFiles) + list (APPEND _contents "#endif") + endif() + if (_option_EPILOGUE) + list (APPEND _contents ${_option_EPILOGUE}) + endif() + list (APPEND _contents "") + string (REPLACE ";" "\n" _contents "${_contents}") + if (COTIRE_VERBOSE) + message ("${_contents}") + endif() + cotire_write_file("${_option_LANGUAGE}" "${_unityFile}" "${_contents}" TRUE) +endfunction() + +function (cotire_generate_prefix_header _prefixFile) + set(_options "") + set(_oneValueArgs LANGUAGE COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_ID COMPILER_VERSION) + set(_multiValueArgs DEPENDS COMPILE_DEFINITIONS COMPILE_FLAGS + INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH + IGNORE_EXTENSIONS INCLUDE_PRIORITY_PATH COMPILER_LAUNCHER) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if (NOT _option_COMPILER_ID) + set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") + endif() + if (NOT _option_COMPILER_VERSION) + set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}") + endif() + if (_option_DEPENDS) + cotire_check_file_up_to_date(_prefixFileIsUpToDate "${_prefixFile}" ${_option_DEPENDS}) + if (_prefixFileIsUpToDate) + # create empty log file + set (_unparsedLinesFile "${_prefixFile}.log") + file (WRITE "${_unparsedLinesFile}" "") + return() + endif() + endif() + set (_prologue "") + set (_epilogue "") + if (_option_COMPILER_ID MATCHES "Clang") + set (_prologue "#pragma clang system_header") + elseif (_option_COMPILER_ID MATCHES "GNU") + set (_prologue "#pragma GCC system_header") + elseif (_option_COMPILER_ID MATCHES "MSVC") + set (_prologue "#pragma warning(push, 0)") + set (_epilogue "#pragma warning(pop)") + elseif (_option_COMPILER_ID MATCHES "Intel") + # Intel compiler requires hdrstop pragma to stop generating PCH file + set (_epilogue "#pragma hdrstop") + endif() + set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) + cotire_scan_includes(_selectedHeaders ${_sourceFiles} + LANGUAGE "${_option_LANGUAGE}" + COMPILER_LAUNCHER "${_option_COMPILER_LAUNCHER}" + COMPILER_EXECUTABLE "${_option_COMPILER_EXECUTABLE}" + COMPILER_ARG1 "${_option_COMPILER_ARG1}" + COMPILER_ID "${_option_COMPILER_ID}" + COMPILER_VERSION "${_option_COMPILER_VERSION}" + COMPILE_DEFINITIONS ${_option_COMPILE_DEFINITIONS} + COMPILE_FLAGS ${_option_COMPILE_FLAGS} + INCLUDE_DIRECTORIES ${_option_INCLUDE_DIRECTORIES} + SYSTEM_INCLUDE_DIRECTORIES ${_option_SYSTEM_INCLUDE_DIRECTORIES} + IGNORE_PATH ${_option_IGNORE_PATH} + INCLUDE_PATH ${_option_INCLUDE_PATH} + IGNORE_EXTENSIONS ${_option_IGNORE_EXTENSIONS} + INCLUDE_PRIORITY_PATH ${_option_INCLUDE_PRIORITY_PATH} + UNPARSED_LINES _unparsedLines + SCAN_RESULT _scanResult) + cotire_generate_unity_source("${_prefixFile}" + PROLOGUE ${_prologue} EPILOGUE ${_epilogue} LANGUAGE "${_option_LANGUAGE}" ${_selectedHeaders}) + set (_unparsedLinesFile "${_prefixFile}.log") + if (_unparsedLines) + if (COTIRE_VERBOSE OR _scanResult OR NOT _selectedHeaders) + list (LENGTH _unparsedLines _skippedLineCount) + message (STATUS "${_skippedLineCount} line(s) skipped, see ${_unparsedLinesFile}") + endif() + string (REPLACE ";" "\n" _unparsedLines "${_unparsedLines}") + endif() + file (WRITE "${_unparsedLinesFile}" "${_unparsedLines}") +endfunction() + +function (cotire_add_makedep_flags _language _compilerID _compilerVersion _flagsVar) + set (_flags ${${_flagsVar}}) + if (_compilerID MATCHES "MSVC") + # cl.exe options used + # /nologo suppresses display of sign-on banner + # /TC treat all files named on the command line as C source files + # /TP treat all files named on the command line as C++ source files + # /EP preprocess to stdout without #line directives + # /showIncludes list include files + set (_sourceFileTypeC "/TC") + set (_sourceFileTypeCXX "/TP") + if (_flags) + # append to list + list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /showIncludes) + else() + # return as a flag string + set (_flags "${_sourceFileType${_language}} /EP /showIncludes") + endif() + elseif (_compilerID MATCHES "GNU") + # GCC options used + # -H print the name of each header file used + # -E invoke preprocessor + # -fdirectives-only do not expand macros, requires GCC >= 4.3 + if (_flags) + # append to list + list (APPEND _flags -H -E) + if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0") + list (APPEND _flags "-fdirectives-only") + endif() + else() + # return as a flag string + set (_flags "-H -E") + if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0") + set (_flags "${_flags} -fdirectives-only") + endif() + endif() + elseif (_compilerID MATCHES "Clang") + # Clang options used + # -H print the name of each header file used + # -E invoke preprocessor + # -fno-color-diagnostics don't prints diagnostics in color + if (_flags) + # append to list + list (APPEND _flags -H -E -fno-color-diagnostics) + else() + # return as a flag string + set (_flags "-H -E -fno-color-diagnostics") + endif() + elseif (_compilerID MATCHES "Intel") + if (WIN32) + # Windows Intel options used + # /nologo do not display compiler version information + # /QH display the include file order + # /EP preprocess to stdout, omitting #line directives + # /TC process all source or unrecognized file types as C source files + # /TP process all source or unrecognized file types as C++ source files + set (_sourceFileTypeC "/TC") + set (_sourceFileTypeCXX "/TP") + if (_flags) + # append to list + list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /QH) + else() + # return as a flag string + set (_flags "${_sourceFileType${_language}} /EP /QH") + endif() + else() + # Linux / Mac OS X Intel options used + # -H print the name of each header file used + # -EP preprocess to stdout, omitting #line directives + # -Kc++ process all source or unrecognized file types as C++ source files + if (_flags) + # append to list + if ("${_language}" STREQUAL "CXX") + list (APPEND _flags -Kc++) + endif() + list (APPEND _flags -H -EP) + else() + # return as a flag string + if ("${_language}" STREQUAL "CXX") + set (_flags "-Kc++ ") + endif() + set (_flags "${_flags}-H -EP") + endif() + endif() + else() + message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") + endif() + set (${_flagsVar} ${_flags} PARENT_SCOPE) +endfunction() + +function (cotire_add_pch_compilation_flags _language _compilerID _compilerVersion _prefixFile _pchFile _hostFile _flagsVar) + set (_flags ${${_flagsVar}}) + if (_compilerID MATCHES "MSVC") + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative) + # cl.exe options used + # /Yc creates a precompiled header file + # /Fp specifies precompiled header binary file name + # /FI forces inclusion of file + # /TC treat all files named on the command line as C source files + # /TP treat all files named on the command line as C++ source files + # /Zs syntax check only + # /Zm precompiled header memory allocation scaling factor + set (_sourceFileTypeC "/TC") + set (_sourceFileTypeCXX "/TP") + if (_flags) + # append to list + list (APPEND _flags /nologo "${_sourceFileType${_language}}" + "/Yc${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}") + if (COTIRE_PCH_MEMORY_SCALING_FACTOR) + list (APPEND _flags "/Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") + endif() + else() + # return as a flag string + set (_flags "/Yc\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") + if (COTIRE_PCH_MEMORY_SCALING_FACTOR) + set (_flags "${_flags} /Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") + endif() + endif() + elseif (_compilerID MATCHES "GNU|Clang") + # GCC / Clang options used + # -x specify the source language + # -c compile but do not link + # -o place output in file + # note that we cannot use -w to suppress all warnings upon pre-compiling, because turning off a warning may + # alter compile flags as a side effect (e.g., -Wwrite-string implies -fconst-strings) + set (_xLanguage_C "c-header") + set (_xLanguage_CXX "c++-header") + if (_flags) + # append to list + list (APPEND _flags "-x" "${_xLanguage_${_language}}" "-c" "${_prefixFile}" -o "${_pchFile}") + else() + # return as a flag string + set (_flags "-x ${_xLanguage_${_language}} -c \"${_prefixFile}\" -o \"${_pchFile}\"") + endif() + elseif (_compilerID MATCHES "Intel") + if (WIN32) + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative) + # Windows Intel options used + # /nologo do not display compiler version information + # /Yc create a precompiled header (PCH) file + # /Fp specify a path or file name for precompiled header files + # /FI tells the preprocessor to include a specified file name as the header file + # /TC process all source or unrecognized file types as C source files + # /TP process all source or unrecognized file types as C++ source files + # /Zs syntax check only + # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) + set (_sourceFileTypeC "/TC") + set (_sourceFileTypeCXX "/TP") + if (_flags) + # append to list + list (APPEND _flags /nologo "${_sourceFileType${_language}}" + "/Yc" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + list (APPEND _flags "/Wpch-messages") + endif() + else() + # return as a flag string + set (_flags "/Yc /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + set (_flags "${_flags} /Wpch-messages") + endif() + endif() + else() + # Linux / Mac OS X Intel options used + # -pch-dir location for precompiled header files + # -pch-create name of the precompiled header (PCH) to create + # -Kc++ process all source or unrecognized file types as C++ source files + # -fsyntax-only check only for correct syntax + # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) + get_filename_component(_pchDir "${_pchFile}" DIRECTORY) + get_filename_component(_pchName "${_pchFile}" NAME) + set (_xLanguage_C "c-header") + set (_xLanguage_CXX "c++-header") + set (_pchSuppressMessages FALSE) + if ("${CMAKE_${_language}_FLAGS}" MATCHES ".*-Wno-pch-messages.*") + set(_pchSuppressMessages TRUE) + endif() + if (_flags) + # append to list + if ("${_language}" STREQUAL "CXX") + list (APPEND _flags -Kc++) + endif() + list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-create" "${_pchName}" "-fsyntax-only" "${_hostFile}") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + if (NOT _pchSuppressMessages) + list (APPEND _flags "-Wpch-messages") + endif() + endif() + else() + # return as a flag string + set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-create \"${_pchName}\"") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + if (NOT _pchSuppressMessages) + set (_flags "${_flags} -Wpch-messages") + endif() + endif() + endif() + endif() + else() + message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") + endif() + set (${_flagsVar} ${_flags} PARENT_SCOPE) +endfunction() + +function (cotire_add_prefix_pch_inclusion_flags _language _compilerID _compilerVersion _prefixFile _pchFile _flagsVar) + set (_flags ${${_flagsVar}}) + if (_compilerID MATCHES "MSVC") + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + # cl.exe options used + # /Yu uses a precompiled header file during build + # /Fp specifies precompiled header binary file name + # /FI forces inclusion of file + # /Zm precompiled header memory allocation scaling factor + if (_pchFile) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + if (_flags) + # append to list + list (APPEND _flags "/Yu${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}") + if (COTIRE_PCH_MEMORY_SCALING_FACTOR) + list (APPEND _flags "/Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") + endif() + else() + # return as a flag string + set (_flags "/Yu\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") + if (COTIRE_PCH_MEMORY_SCALING_FACTOR) + set (_flags "${_flags} /Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") + endif() + endif() + else() + # no precompiled header, force inclusion of prefix header + if (_flags) + # append to list + list (APPEND _flags "/FI${_prefixFileNative}") + else() + # return as a flag string + set (_flags "/FI\"${_prefixFileNative}\"") + endif() + endif() + elseif (_compilerID MATCHES "GNU") + # GCC options used + # -include process include file as the first line of the primary source file + # -Winvalid-pch warns if precompiled header is found but cannot be used + # note: ccache requires the -include flag to be used in order to process precompiled header correctly + if (_flags) + # append to list + list (APPEND _flags "-Winvalid-pch" "-include" "${_prefixFile}") + else() + # return as a flag string + set (_flags "-Winvalid-pch -include \"${_prefixFile}\"") + endif() + elseif (_compilerID MATCHES "Clang") + # Clang options used + # -include process include file as the first line of the primary source file + # -include-pch include precompiled header file + # -Qunused-arguments don't emit warning for unused driver arguments + # note: ccache requires the -include flag to be used in order to process precompiled header correctly + if (_flags) + # append to list + list (APPEND _flags "-Qunused-arguments" "-include" "${_prefixFile}") + else() + # return as a flag string + set (_flags "-Qunused-arguments -include \"${_prefixFile}\"") + endif() + elseif (_compilerID MATCHES "Intel") + if (WIN32) + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) + # Windows Intel options used + # /Yu use a precompiled header (PCH) file + # /Fp specify a path or file name for precompiled header files + # /FI tells the preprocessor to include a specified file name as the header file + # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) + if (_pchFile) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) + if (_flags) + # append to list + list (APPEND _flags "/Yu" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + list (APPEND _flags "/Wpch-messages") + endif() + else() + # return as a flag string + set (_flags "/Yu /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + set (_flags "${_flags} /Wpch-messages") + endif() + endif() + else() + # no precompiled header, force inclusion of prefix header + if (_flags) + # append to list + list (APPEND _flags "/FI${_prefixFileNative}") + else() + # return as a flag string + set (_flags "/FI\"${_prefixFileNative}\"") + endif() + endif() + else() + # Linux / Mac OS X Intel options used + # -pch-dir location for precompiled header files + # -pch-use name of the precompiled header (PCH) to use + # -include process include file as the first line of the primary source file + # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) + if (_pchFile) + get_filename_component(_pchDir "${_pchFile}" DIRECTORY) + get_filename_component(_pchName "${_pchFile}" NAME) + set (_pchSuppressMessages FALSE) + if ("${CMAKE_${_language}_FLAGS}" MATCHES ".*-Wno-pch-messages.*") + set(_pchSuppressMessages TRUE) + endif() + if (_flags) + # append to list + list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-use" "${_pchName}") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + if (NOT _pchSuppressMessages) + list (APPEND _flags "-Wpch-messages") + endif() + endif() + else() + # return as a flag string + set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-use \"${_pchName}\"") + if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") + if (NOT _pchSuppressMessages) + set (_flags "${_flags} -Wpch-messages") + endif() + endif() + endif() + else() + # no precompiled header, force inclusion of prefix header + if (_flags) + # append to list + list (APPEND _flags "-include" "${_prefixFile}") + else() + # return as a flag string + set (_flags "-include \"${_prefixFile}\"") + endif() + endif() + endif() + else() + message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") + endif() + set (${_flagsVar} ${_flags} PARENT_SCOPE) +endfunction() + +function (cotire_precompile_prefix_header _prefixFile _pchFile _hostFile) + set(_options "") + set(_oneValueArgs COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_ID COMPILER_VERSION LANGUAGE) + set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES SYS COMPILER_LAUNCHER) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if (NOT _option_LANGUAGE) + set (_option_LANGUAGE "CXX") + endif() + if (NOT _option_COMPILER_ID) + set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") + endif() + if (NOT _option_COMPILER_VERSION) + set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}") + endif() + cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_LAUNCHER}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}") + cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS}) + cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS}) + cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) + cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) + cotire_add_pch_compilation_flags( + "${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" "${_hostFile}" _cmd) + if (COTIRE_VERBOSE) + message (STATUS "execute_process: ${_cmd}") + endif() + if (_option_COMPILER_ID MATCHES "MSVC") + # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared + unset (ENV{VS_UNICODE_OUTPUT}) + elseif (_option_COMPILER_ID MATCHES "GNU|Clang") + if (_option_COMPILER_LAUNCHER MATCHES "ccache" OR + _option_COMPILER_EXECUTABLE MATCHES "ccache") + # Newer versions of Clang and GCC seem to embed a compilation timestamp into the precompiled header binary, + # which results in "file has been modified since the precompiled header was built" errors if ccache is used. + # We work around the problem by disabling ccache upon pre-compiling the prefix header. + set (ENV{CCACHE_DISABLE} "true") + endif() + endif() + execute_process( + COMMAND ${_cmd} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE _result) + if (_result) + message (FATAL_ERROR "cotire: error ${_result} precompiling ${_prefixFile}.") + endif() +endfunction() + +function (cotire_check_precompiled_header_support _language _target _msgVar) + set (_unsupportedCompiler + "Precompiled headers not supported for ${_language} compiler ${CMAKE_${_language}_COMPILER_ID}") + if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC") + # supported since Visual Studio C++ 6.0 + # and CMake does not support an earlier version + set (${_msgVar} "" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU") + # GCC PCH support requires version >= 3.4 + if ("${CMAKE_${_language}_COMPILER_VERSION}" VERSION_LESS "3.4.0") + set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}." PARENT_SCOPE) + else() + set (${_msgVar} "" PARENT_SCOPE) + endif() + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang") + # all Clang versions have PCH support + set (${_msgVar} "" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel") + # Intel PCH support requires version >= 8.0.0 + if ("${CMAKE_${_language}_COMPILER_VERSION}" VERSION_LESS "8.0.0") + set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}." PARENT_SCOPE) + else() + set (${_msgVar} "" PARENT_SCOPE) + endif() + else() + set (${_msgVar} "${_unsupportedCompiler}." PARENT_SCOPE) + endif() + get_target_property(_launcher ${_target} ${_language}_COMPILER_LAUNCHER) + if (CMAKE_${_language}_COMPILER MATCHES "ccache" OR _launcher MATCHES "ccache") + if (DEFINED ENV{CCACHE_SLOPPINESS}) + if (NOT "$ENV{CCACHE_SLOPPINESS}" MATCHES "pch_defines" OR NOT "$ENV{CCACHE_SLOPPINESS}" MATCHES "time_macros") + set (${_msgVar} + "ccache requires the environment variable CCACHE_SLOPPINESS to be set to \"pch_defines,time_macros\"." + PARENT_SCOPE) + endif() + else() + if (_launcher MATCHES "ccache") + get_filename_component(_ccacheExe "${_launcher}" REALPATH) + else() + get_filename_component(_ccacheExe "${CMAKE_${_language}_COMPILER}" REALPATH) + endif() + execute_process( + COMMAND "${_ccacheExe}" "--print-config" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + RESULT_VARIABLE _result + OUTPUT_VARIABLE _ccacheConfig OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) + if (_result OR NOT + _ccacheConfig MATCHES "sloppiness.*=.*time_macros" OR NOT + _ccacheConfig MATCHES "sloppiness.*=.*pch_defines") + set (${_msgVar} + "ccache requires configuration setting \"sloppiness\" to be set to \"pch_defines,time_macros\"." + PARENT_SCOPE) + endif() + endif() + endif() + if (APPLE) + # PCH compilation not supported by GCC / Clang for multi-architecture builds (e.g., i386, x86_64) + cotire_get_configuration_types(_configs) + foreach (_config ${_configs}) + set (_targetFlags "") + cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) + cotire_filter_compile_flags("${_language}" "arch" _architectures _ignore ${_targetFlags}) + list (LENGTH _architectures _numberOfArchitectures) + if (_numberOfArchitectures GREATER 1) + string (REPLACE ";" ", " _architectureStr "${_architectures}") + set (${_msgVar} + "Precompiled headers not supported on Darwin for multi-architecture builds (${_architectureStr})." + PARENT_SCOPE) + break() + endif() + endforeach() + endif() +endfunction() + +macro (cotire_get_intermediate_dir _cotireDir) + # ${CMAKE_CFG_INTDIR} may reference a build-time variable when using a generator which supports configuration types + get_filename_component(${_cotireDir} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${COTIRE_INTDIR}" ABSOLUTE) +endmacro() + +macro (cotire_setup_file_extension_variables) + set (_unityFileExt_C ".c") + set (_unityFileExt_CXX ".cxx") + set (_prefixFileExt_C ".h") + set (_prefixFileExt_CXX ".hxx") + set (_prefixSourceFileExt_C ".c") + set (_prefixSourceFileExt_CXX ".cxx") +endmacro() + +function (cotire_make_single_unity_source_file_path _language _target _unityFileVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _unityFileExt_${_language}) + set (${_unityFileVar} "" PARENT_SCOPE) + return() + endif() + set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") + set (_unityFileName "${_unityFileBaseName}${_unityFileExt_${_language}}") + cotire_get_intermediate_dir(_baseDir) + set (_unityFile "${_baseDir}/${_unityFileName}") + set (${_unityFileVar} "${_unityFile}" PARENT_SCOPE) +endfunction() + +function (cotire_make_unity_source_file_paths _language _target _maxIncludes _unityFilesVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _unityFileExt_${_language}) + set (${_unityFileVar} "" PARENT_SCOPE) + return() + endif() + set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") + cotire_get_intermediate_dir(_baseDir) + set (_startIndex 0) + set (_index 0) + set (_unityFiles "") + set (_sourceFiles ${ARGN}) + foreach (_sourceFile ${_sourceFiles}) + get_source_file_property(_startNew "${_sourceFile}" COTIRE_START_NEW_UNITY_SOURCE) + math (EXPR _unityFileCount "${_index} - ${_startIndex}") + if (_startNew OR (_maxIncludes GREATER 0 AND NOT _unityFileCount LESS _maxIncludes)) + if (_index GREATER 0) + # start new unity file segment + math (EXPR _endIndex "${_index} - 1") + set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}") + list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") + endif() + set (_startIndex ${_index}) + endif() + math (EXPR _index "${_index} + 1") + endforeach() + list (LENGTH _sourceFiles _numberOfSources) + if (_startIndex EQUAL 0) + # there is only a single unity file + cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFiles) + elseif (_startIndex LESS _numberOfSources) + # end with final unity file segment + math (EXPR _endIndex "${_index} - 1") + set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}") + list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") + endif() + set (${_unityFilesVar} ${_unityFiles} PARENT_SCOPE) + if (COTIRE_DEBUG AND _unityFiles) + message (STATUS "unity files: ${_unityFiles}") + endif() +endfunction() + +function (cotire_unity_to_prefix_file_path _language _target _unityFile _prefixFileVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _unityFileExt_${_language}) + set (${_prefixFileVar} "" PARENT_SCOPE) + return() + endif() + set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") + set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") + string (REPLACE "${_unityFileBaseName}" "${_prefixFileBaseName}" _prefixFile "${_unityFile}") + string (REGEX REPLACE "${_unityFileExt_${_language}}$" "${_prefixFileExt_${_language}}" _prefixFile "${_prefixFile}") + set (${_prefixFileVar} "${_prefixFile}" PARENT_SCOPE) +endfunction() + +function (cotire_prefix_header_to_source_file_path _language _prefixHeaderFile _prefixSourceFileVar) + cotire_setup_file_extension_variables() + if (NOT DEFINED _prefixSourceFileExt_${_language}) + set (${_prefixSourceFileVar} "" PARENT_SCOPE) + return() + endif() + string (REGEX REPLACE "${_prefixFileExt_${_language}}$" "${_prefixSourceFileExt_${_language}}" _prefixSourceFile "${_prefixHeaderFile}") + set (${_prefixSourceFileVar} "${_prefixSourceFile}" PARENT_SCOPE) +endfunction() + +function (cotire_make_prefix_file_name _language _target _prefixFileBaseNameVar _prefixFileNameVar) + cotire_setup_file_extension_variables() + if (NOT _language) + set (_prefixFileBaseName "${_target}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") + set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_C}") + elseif (DEFINED _prefixFileExt_${_language}) + set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") + set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_${_language}}") + else() + set (_prefixFileBaseName "") + set (_prefixFileName "") + endif() + set (${_prefixFileBaseNameVar} "${_prefixFileBaseName}" PARENT_SCOPE) + set (${_prefixFileNameVar} "${_prefixFileName}" PARENT_SCOPE) +endfunction() + +function (cotire_make_prefix_file_path _language _target _prefixFileVar) + cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName) + set (${_prefixFileVar} "" PARENT_SCOPE) + if (_prefixFileName) + if (NOT _language) + set (_language "C") + endif() + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang|Intel|MSVC") + cotire_get_intermediate_dir(_baseDir) + set (${_prefixFileVar} "${_baseDir}/${_prefixFileName}" PARENT_SCOPE) + endif() + endif() +endfunction() + +function (cotire_make_pch_file_path _language _target _pchFileVar) + cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName) + set (${_pchFileVar} "" PARENT_SCOPE) + if (_prefixFileBaseName AND _prefixFileName) + cotire_check_precompiled_header_support("${_language}" "${_target}" _msg) + if (NOT _msg) + if (XCODE) + # For Xcode, we completely hand off the compilation of the prefix header to the IDE + return() + endif() + cotire_get_intermediate_dir(_baseDir) + if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC") + # MSVC uses the extension .pch added to the prefix header base name + set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pch" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang") + # Clang looks for a precompiled header corresponding to the prefix header with the extension .pch appended + set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.pch" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU") + # GCC looks for a precompiled header corresponding to the prefix header with the extension .gch appended + set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.gch" PARENT_SCOPE) + elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel") + # Intel uses the extension .pchi added to the prefix header base name + set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pchi" PARENT_SCOPE) + endif() + endif() + endif() +endfunction() + +function (cotire_select_unity_source_files _unityFile _sourcesVar) + set (_sourceFiles ${ARGN}) + if (_sourceFiles AND "${_unityFile}" MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}_([0-9]+)_([0-9]+)") + set (_startIndex ${CMAKE_MATCH_1}) + set (_endIndex ${CMAKE_MATCH_2}) + list (LENGTH _sourceFiles _numberOfSources) + if (NOT _startIndex LESS _numberOfSources) + math (EXPR _startIndex "${_numberOfSources} - 1") + endif() + if (NOT _endIndex LESS _numberOfSources) + math (EXPR _endIndex "${_numberOfSources} - 1") + endif() + set (_files "") + foreach (_index RANGE ${_startIndex} ${_endIndex}) + list (GET _sourceFiles ${_index} _file) + list (APPEND _files "${_file}") + endforeach() + else() + set (_files ${_sourceFiles}) + endif() + set (${_sourcesVar} ${_files} PARENT_SCOPE) +endfunction() + +function (cotire_get_unity_source_dependencies _language _target _dependencySourcesVar) + set (_dependencySources "") + # depend on target's generated source files + get_target_property(_targetSourceFiles ${_target} SOURCES) + cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${_targetSourceFiles}) + if (_generatedSources) + # but omit all generated source files that have the COTIRE_EXCLUDED property set to true + cotire_get_objects_with_property_on(_excludedGeneratedSources COTIRE_EXCLUDED SOURCE ${_generatedSources}) + if (_excludedGeneratedSources) + list (REMOVE_ITEM _generatedSources ${_excludedGeneratedSources}) + endif() + # and omit all generated source files that have the COTIRE_DEPENDENCY property set to false explicitly + cotire_get_objects_with_property_off(_excludedNonDependencySources COTIRE_DEPENDENCY SOURCE ${_generatedSources}) + if (_excludedNonDependencySources) + list (REMOVE_ITEM _generatedSources ${_excludedNonDependencySources}) + endif() + if (_generatedSources) + list (APPEND _dependencySources ${_generatedSources}) + endif() + endif() + if (COTIRE_DEBUG AND _dependencySources) + message (STATUS "${_language} ${_target} unity source dependencies: ${_dependencySources}") + endif() + set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE) +endfunction() + +function (cotire_get_prefix_header_dependencies _language _target _dependencySourcesVar) + set (_dependencySources "") + # depend on target source files marked with custom COTIRE_DEPENDENCY property + get_target_property(_targetSourceFiles ${_target} SOURCES) + cotire_get_objects_with_property_on(_dependencySources COTIRE_DEPENDENCY SOURCE ${_targetSourceFiles}) + if (COTIRE_DEBUG AND _dependencySources) + message (STATUS "${_language} ${_target} prefix header dependencies: ${_dependencySources}") + endif() + set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE) +endfunction() + +function (cotire_generate_target_script _language _configurations _target _targetScriptVar _targetConfigScriptVar) + set (_targetSources ${ARGN}) + cotire_get_prefix_header_dependencies(${_language} ${_target} COTIRE_TARGET_PREFIX_DEPENDS ${_targetSources}) + cotire_get_unity_source_dependencies(${_language} ${_target} COTIRE_TARGET_UNITY_DEPENDS ${_targetSources}) + # set up variables to be configured + set (COTIRE_TARGET_LANGUAGE "${_language}") + get_target_property(COTIRE_TARGET_IGNORE_PATH ${_target} COTIRE_PREFIX_HEADER_IGNORE_PATH) + cotire_add_sys_root_paths(COTIRE_TARGET_IGNORE_PATH) + get_target_property(COTIRE_TARGET_INCLUDE_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PATH) + cotire_add_sys_root_paths(COTIRE_TARGET_INCLUDE_PATH) + get_target_property(COTIRE_TARGET_PRE_UNDEFS ${_target} COTIRE_UNITY_SOURCE_PRE_UNDEFS) + get_target_property(COTIRE_TARGET_POST_UNDEFS ${_target} COTIRE_UNITY_SOURCE_POST_UNDEFS) + get_target_property(COTIRE_TARGET_MAXIMUM_NUMBER_OF_INCLUDES ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) + get_target_property(COTIRE_TARGET_INCLUDE_PRIORITY_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH) + cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_PRE_UNDEFS COTIRE_TARGET_SOURCES_PRE_UNDEFS ${_targetSources}) + cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_POST_UNDEFS COTIRE_TARGET_SOURCES_POST_UNDEFS ${_targetSources}) + set (COTIRE_TARGET_CONFIGURATION_TYPES "${_configurations}") + foreach (_config ${_configurations}) + string (TOUPPER "${_config}" _upperConfig) + cotire_get_target_include_directories( + "${_config}" "${_language}" "${_target}" COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig} COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}) + cotire_get_target_compile_definitions( + "${_config}" "${_language}" "${_target}" COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}) + cotire_get_target_compiler_flags( + "${_config}" "${_language}" "${_target}" COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}) + cotire_get_source_files_compile_definitions( + "${_config}" "${_language}" COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig} ${_targetSources}) + endforeach() + get_target_property(COTIRE_TARGET_${_language}_COMPILER_LAUNCHER ${_target} ${_language}_COMPILER_LAUNCHER) + # set up COTIRE_TARGET_SOURCES + set (COTIRE_TARGET_SOURCES "") + foreach (_sourceFile ${_targetSources}) + get_source_file_property(_generated "${_sourceFile}" GENERATED) + if (_generated) + # use absolute paths for generated files only, retrieving the LOCATION property is an expensive operation + get_source_file_property(_sourceLocation "${_sourceFile}" LOCATION) + list (APPEND COTIRE_TARGET_SOURCES "${_sourceLocation}") + else() + list (APPEND COTIRE_TARGET_SOURCES "${_sourceFile}") + endif() + endforeach() + # copy variable definitions to cotire target script + get_cmake_property(_vars VARIABLES) + string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+" _matchVars "${_vars}") + # omit COTIRE_*_INIT variables + string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+_INIT" _initVars "${_matchVars}") + if (_initVars) + list (REMOVE_ITEM _matchVars ${_initVars}) + endif() + # omit COTIRE_VERBOSE which is passed as a CMake define on command line + list (REMOVE_ITEM _matchVars COTIRE_VERBOSE) + set (_contents "") + set (_contentsHasGeneratorExpressions FALSE) + foreach (_var IN LISTS _matchVars ITEMS + XCODE MSVC CMAKE_GENERATOR CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES + CMAKE_${_language}_COMPILER_ID CMAKE_${_language}_COMPILER_VERSION + CMAKE_${_language}_COMPILER_LAUNCHER CMAKE_${_language}_COMPILER CMAKE_${_language}_COMPILER_ARG1 + CMAKE_INCLUDE_FLAG_${_language} CMAKE_INCLUDE_FLAG_SEP_${_language} + CMAKE_INCLUDE_SYSTEM_FLAG_${_language} + CMAKE_${_language}_FRAMEWORK_SEARCH_FLAG + CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG + CMAKE_${_language}_SOURCE_FILE_EXTENSIONS) + if (DEFINED ${_var}) + string (REPLACE "\"" "\\\"" _value "${${_var}}") + set (_contents "${_contents}set (${_var} \"${_value}\")\n") + if (NOT _contentsHasGeneratorExpressions) + if ("${_value}" MATCHES "\\$<.*>") + set (_contentsHasGeneratorExpressions TRUE) + endif() + endif() + endif() + endforeach() + # generate target script file + get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME) + set (_targetCotireScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_moduleName}") + cotire_write_file("CMAKE" "${_targetCotireScript}" "${_contents}" FALSE) + if (_contentsHasGeneratorExpressions) + # use file(GENERATE ...) to expand generator expressions in the target script at CMake generate-time + set (_configNameOrNoneGeneratorExpression "$<$:None>$<$>:$>") + set (_targetCotireConfigScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_configNameOrNoneGeneratorExpression}_${_moduleName}") + file (GENERATE OUTPUT "${_targetCotireConfigScript}" INPUT "${_targetCotireScript}") + else() + set (_targetCotireConfigScript "${_targetCotireScript}") + endif() + set (${_targetScriptVar} "${_targetCotireScript}" PARENT_SCOPE) + set (${_targetConfigScriptVar} "${_targetCotireConfigScript}" PARENT_SCOPE) +endfunction() + +function (cotire_setup_pch_file_compilation _language _target _targetScript _prefixFile _pchFile _hostFile) + set (_sourceFiles ${ARGN}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + # for Visual Studio and Intel, we attach the precompiled header compilation to the host file + # the remaining files include the precompiled header, see cotire_setup_pch_file_inclusion + if (_sourceFiles) + set (_flags "") + cotire_add_pch_compilation_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" "${_hostFile}" _flags) + set_property (SOURCE ${_hostFile} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_OUTPUTS "${_pchFile}") + # make object file generated from host file depend on prefix header + set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}") + # mark host file as cotired to prevent it from being used in another cotired target + set_property (SOURCE ${_hostFile} PROPERTY COTIRE_TARGET "${_target}") + endif() + elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") + # for makefile based generator, we add a custom command to precompile the prefix header + if (_targetScript) + cotire_set_cmd_to_prologue(_cmds) + list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "precompile" "${_targetScript}" "${_prefixFile}" "${_pchFile}" "${_hostFile}") + if (MSVC_IDE) + file (TO_NATIVE_PATH "${_pchFile}" _pchFileLogPath) + else() + file (RELATIVE_PATH _pchFileLogPath "${CMAKE_BINARY_DIR}" "${_pchFile}") + endif() + # make precompiled header compilation depend on the actual compiler executable used to force + # re-compilation when the compiler executable is updated. This prevents "created by a different GCC executable" + # warnings when the precompiled header is included. + get_filename_component(_realCompilerExe "${CMAKE_${_language}_COMPILER}" ABSOLUTE) + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_pchFile} ${_cmds} DEPENDS ${_prefixFile} ${_realCompilerExe} IMPLICIT_DEPENDS ${_language} ${_prefixFile}") + endif() + set_property (SOURCE "${_pchFile}" PROPERTY GENERATED TRUE) + add_custom_command( + OUTPUT "${_pchFile}" + COMMAND ${_cmds} + DEPENDS "${_prefixFile}" "${_realCompilerExe}" + IMPLICIT_DEPENDS ${_language} "${_prefixFile}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Building ${_language} precompiled header ${_pchFileLogPath}" + VERBATIM) + endif() + endif() +endfunction() + +function (cotire_setup_pch_file_inclusion _language _target _wholeTarget _prefixFile _pchFile _hostFile) + if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + # for Visual Studio and Intel, we include the precompiled header in all but the host file + # the host file does the precompiled header compilation, see cotire_setup_pch_file_compilation + set (_sourceFiles ${ARGN}) + list (LENGTH _sourceFiles _numberOfSourceFiles) + if (_numberOfSourceFiles GREATER 0) + # mark sources as cotired to prevent them from being used in another cotired target + set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") + set (_flags "") + cotire_add_prefix_pch_inclusion_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" _flags) + set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + # make object files generated from source files depend on precompiled header + set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}") + endif() + elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") + set (_sourceFiles ${_hostFile} ${ARGN}) + if (NOT _wholeTarget) + # for makefile based generator, we force the inclusion of the prefix header for a subset + # of the source files, if this is a multi-language target or has excluded files + set (_flags "") + cotire_add_prefix_pch_inclusion_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" _flags) + set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + # mark sources as cotired to prevent them from being used in another cotired target + set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") + endif() + # make object files generated from source files depend on precompiled header + set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}") + endif() +endfunction() + +function (cotire_setup_prefix_file_inclusion _language _target _prefixFile) + set (_sourceFiles ${ARGN}) + # force the inclusion of the prefix header for the given source files + set (_flags "") + set (_pchFile "") + cotire_add_prefix_pch_inclusion_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" _flags) + set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") + # mark sources as cotired to prevent them from being used in another cotired target + set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") + # make object files generated from source files depend on prefix header + set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}") +endfunction() + +function (cotire_get_first_set_property_value _propertyValueVar _type _object) + set (_properties ${ARGN}) + foreach (_property ${_properties}) + get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) + if (_propertyValue) + set (${_propertyValueVar} ${_propertyValue} PARENT_SCOPE) + return() + endif() + endforeach() + set (${_propertyValueVar} "" PARENT_SCOPE) +endfunction() + +function (cotire_setup_combine_command _language _targetScript _joinedFile _cmdsVar) + set (_files ${ARGN}) + set (_filesPaths "") + foreach (_file ${_files}) + get_filename_component(_filePath "${_file}" ABSOLUTE) + list (APPEND _filesPaths "${_filePath}") + endforeach() + cotire_set_cmd_to_prologue(_prefixCmd) + list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "combine") + if (_targetScript) + list (APPEND _prefixCmd "${_targetScript}") + endif() + list (APPEND _prefixCmd "${_joinedFile}" ${_filesPaths}) + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_joinedFile} COMMAND ${_prefixCmd} DEPENDS ${_files}") + endif() + set_property (SOURCE "${_joinedFile}" PROPERTY GENERATED TRUE) + if (MSVC_IDE) + file (TO_NATIVE_PATH "${_joinedFile}" _joinedFileLogPath) + else() + file (RELATIVE_PATH _joinedFileLogPath "${CMAKE_BINARY_DIR}" "${_joinedFile}") + endif() + get_filename_component(_joinedFileBaseName "${_joinedFile}" NAME_WE) + get_filename_component(_joinedFileExt "${_joinedFile}" EXT) + if (_language AND _joinedFileBaseName MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}$") + set (_comment "Generating ${_language} unity source ${_joinedFileLogPath}") + elseif (_language AND _joinedFileBaseName MATCHES "${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}$") + if (_joinedFileExt MATCHES "^\\.c") + set (_comment "Generating ${_language} prefix source ${_joinedFileLogPath}") + else() + set (_comment "Generating ${_language} prefix header ${_joinedFileLogPath}") + endif() + else() + set (_comment "Generating ${_joinedFileLogPath}") + endif() + add_custom_command( + OUTPUT "${_joinedFile}" + COMMAND ${_prefixCmd} + DEPENDS ${_files} + COMMENT "${_comment}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + VERBATIM) + list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_target_pch_usage _languages _target _wholeTarget) + if (XCODE) + # for Xcode, we attach a pre-build action to generate the unity sources and prefix headers + set (_prefixFiles "") + foreach (_language ${_languages}) + get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) + if (_prefixFile) + list (APPEND _prefixFiles "${_prefixFile}") + endif() + endforeach() + set (_cmds ${ARGN}) + list (LENGTH _prefixFiles _numberOfPrefixFiles) + if (_numberOfPrefixFiles GREATER 1) + # we also generate a generic, single prefix header which includes all language specific prefix headers + set (_language "") + set (_targetScript "") + cotire_make_prefix_file_path("${_language}" ${_target} _prefixHeader) + cotire_setup_combine_command("${_language}" "${_targetScript}" "${_prefixHeader}" _cmds ${_prefixFiles}) + else() + set (_prefixHeader "${_prefixFiles}") + endif() + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: TARGET ${_target} PRE_BUILD ${_cmds}") + endif() + # because CMake PRE_BUILD command does not support dependencies, + # we check dependencies explicity in cotire script mode when the pre-build action is run + add_custom_command( + TARGET "${_target}" + PRE_BUILD ${_cmds} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Updating target ${_target} prefix headers" + VERBATIM) + # make Xcode precompile the generated prefix header with ProcessPCH and ProcessPCH++ + set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES") + set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${_prefixHeader}") + elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") + # for makefile based generator, we force inclusion of the prefix header for all target source files + # if this is a single-language target without any excluded files + if (_wholeTarget) + set (_language "${_languages}") + # for Visual Studio and Intel, precompiled header inclusion is always done on the source file level + # see cotire_setup_pch_file_inclusion + if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) + if (_prefixFile) + get_property(_pchFile TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER) + set (_options COMPILE_OPTIONS) + cotire_add_prefix_pch_inclusion_flags( + "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" + "${_prefixFile}" "${_pchFile}" _options) + set_property(TARGET ${_target} APPEND PROPERTY ${_options}) + endif() + endif() + endif() + endif() +endfunction() + +function (cotire_setup_unity_generation_commands _language _target _targetScript _targetConfigScript _unityFiles _cmdsVar) + set (_dependencySources "") + cotire_get_unity_source_dependencies(${_language} ${_target} _dependencySources ${ARGN}) + foreach (_unityFile ${_unityFiles}) + set_property (SOURCE "${_unityFile}" PROPERTY GENERATED TRUE) + # set up compiled unity source dependencies via OBJECT_DEPENDS + # this ensures that missing source files are generated before the unity file is compiled + if (COTIRE_DEBUG AND _dependencySources) + message (STATUS "${_unityFile} OBJECT_DEPENDS ${_dependencySources}") + endif() + if (_dependencySources) + # the OBJECT_DEPENDS property requires a list of full paths + set (_objectDependsPaths "") + foreach (_sourceFile ${_dependencySources}) + get_source_file_property(_sourceLocation "${_sourceFile}" LOCATION) + list (APPEND _objectDependsPaths "${_sourceLocation}") + endforeach() + set_property (SOURCE "${_unityFile}" PROPERTY OBJECT_DEPENDS ${_objectDependsPaths}) + endif() + if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + # unity file compilation results in potentially huge object file, thus use /bigobj by default unter MSVC and Windows Intel + set_property (SOURCE "${_unityFile}" APPEND_STRING PROPERTY COMPILE_FLAGS "/bigobj") + endif() + cotire_set_cmd_to_prologue(_unityCmd) + list (APPEND _unityCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "unity" "${_targetConfigScript}" "${_unityFile}") + if (CMAKE_VERSION VERSION_LESS "3.1.0") + set (_unityCmdDepends "${_targetScript}") + else() + # CMake 3.1.0 supports generator expressions in arguments to DEPENDS + set (_unityCmdDepends "${_targetConfigScript}") + endif() + if (MSVC_IDE) + file (TO_NATIVE_PATH "${_unityFile}" _unityFileLogPath) + else() + file (RELATIVE_PATH _unityFileLogPath "${CMAKE_BINARY_DIR}" "${_unityFile}") + endif() + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_unityFile} COMMAND ${_unityCmd} DEPENDS ${_unityCmdDepends}") + endif() + add_custom_command( + OUTPUT "${_unityFile}" + COMMAND ${_unityCmd} + DEPENDS ${_unityCmdDepends} + COMMENT "Generating ${_language} unity source ${_unityFileLogPath}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + VERBATIM) + list (APPEND ${_cmdsVar} COMMAND ${_unityCmd}) + endforeach() + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_prefix_generation_command _language _target _targetScript _prefixFile _unityFiles _cmdsVar) + set (_sourceFiles ${ARGN}) + set (_dependencySources "") + cotire_get_prefix_header_dependencies(${_language} ${_target} _dependencySources ${_sourceFiles}) + cotire_set_cmd_to_prologue(_prefixCmd) + list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "prefix" "${_targetScript}" "${_prefixFile}" ${_unityFiles}) + set_property (SOURCE "${_prefixFile}" PROPERTY GENERATED TRUE) + # make prefix header generation depend on the actual compiler executable used to force + # re-generation when the compiler executable is updated. This prevents "file not found" + # errors for compiler version specific system header files. + get_filename_component(_realCompilerExe "${CMAKE_${_language}_COMPILER}" ABSOLUTE) + if (COTIRE_DEBUG) + message (STATUS "add_custom_command: OUTPUT ${_prefixFile} COMMAND ${_prefixCmd} DEPENDS ${_unityFile} ${_dependencySources} ${_realCompilerExe}") + endif() + if (MSVC_IDE) + file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileLogPath) + else() + file (RELATIVE_PATH _prefixFileLogPath "${CMAKE_BINARY_DIR}" "${_prefixFile}") + endif() + get_filename_component(_prefixFileExt "${_prefixFile}" EXT) + if (_prefixFileExt MATCHES "^\\.c") + set (_comment "Generating ${_language} prefix source ${_prefixFileLogPath}") + else() + set (_comment "Generating ${_language} prefix header ${_prefixFileLogPath}") + endif() + # prevent pre-processing errors upon generating the prefix header when a target's generated include file does not yet exist + # we do not add a file-level dependency for the target's generated files though, because we only want to depend on their existence + # thus we make the prefix header generation depend on a custom helper target which triggers the generation of the files + set (_preTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}_pre") + if (TARGET ${_preTargetName}) + # custom helper target has already been generated while processing a different language + list (APPEND _dependencySources ${_preTargetName}) + else() + get_target_property(_targetSourceFiles ${_target} SOURCES) + cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${_targetSourceFiles}) + if (_generatedSources) + add_custom_target("${_preTargetName}" DEPENDS ${_generatedSources}) + cotire_init_target("${_preTargetName}") + list (APPEND _dependencySources ${_preTargetName}) + endif() + endif() + add_custom_command( + OUTPUT "${_prefixFile}" "${_prefixFile}.log" + COMMAND ${_prefixCmd} + DEPENDS ${_unityFiles} ${_dependencySources} "${_realCompilerExe}" + COMMENT "${_comment}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + VERBATIM) + list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_prefix_generation_from_unity_command _language _target _targetScript _prefixFile _unityFiles _cmdsVar) + set (_sourceFiles ${ARGN}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma + cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile) + else() + set (_prefixSourceFile "${_prefixFile}") + endif() + cotire_setup_prefix_generation_command( + ${_language} ${_target} "${_targetScript}" + "${_prefixSourceFile}" "${_unityFiles}" ${_cmdsVar} ${_sourceFiles}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + # set up generation of a prefix source file which includes the prefix header + cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile}) + endif() + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_setup_prefix_generation_from_provided_command _language _target _targetScript _prefixFile _cmdsVar) + set (_prefixHeaderFiles ${ARGN}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma + cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile) + else() + set (_prefixSourceFile "${_prefixFile}") + endif() + cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixSourceFile}" _cmds ${_prefixHeaderFiles}) + if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") + # set up generation of a prefix source file which includes the prefix header + cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile}) + endif() + set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) +endfunction() + +function (cotire_init_cotire_target_properties _target) + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER TRUE) + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD TRUE) + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN FALSE) + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_SOURCE_DIR}") + cotire_check_is_path_relative_to("${CMAKE_BINARY_DIR}" _isRelative "${CMAKE_SOURCE_DIR}") + if (NOT _isRelative) + set_property(TARGET ${_target} APPEND PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_BINARY_DIR}") + endif() + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH "") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH "") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS "") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS "") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT SET) + if (NOT _isSet) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT "COPY_UNITY") + endif() + get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES SET) + if (NOT _isSet) + if (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}") + else() + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "") + endif() + endif() +endfunction() + +function (cotire_make_target_message _target _languages _disableMsg _targetMsgVar) + get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) + get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) + string (REPLACE ";" " " _languagesStr "${_languages}") + math (EXPR _numberOfExcludedFiles "${ARGC} - 4") + if (_numberOfExcludedFiles EQUAL 0) + set (_excludedStr "") + elseif (COTIRE_VERBOSE OR _numberOfExcludedFiles LESS 4) + string (REPLACE ";" ", " _excludedStr "excluding ${ARGN}") + else() + set (_excludedStr "excluding ${_numberOfExcludedFiles} files") + endif() + set (_targetMsg "") + if (NOT _languages) + set (_targetMsg "Target ${_target} cannot be cotired.") + if (_disableMsg) + set (_targetMsg "${_targetMsg} ${_disableMsg}") + endif() + elseif (NOT _targetUsePCH AND NOT _targetAddSCU) + set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build and precompiled header.") + if (_disableMsg) + set (_targetMsg "${_targetMsg} ${_disableMsg}") + endif() + elseif (NOT _targetUsePCH) + if (_excludedStr) + set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header ${_excludedStr}.") + else() + set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header.") + endif() + if (_disableMsg) + set (_targetMsg "${_targetMsg} ${_disableMsg}") + endif() + elseif (NOT _targetAddSCU) + if (_excludedStr) + set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build ${_excludedStr}.") + else() + set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build.") + endif() + else() + if (_excludedStr) + set (_targetMsg "${_languagesStr} target ${_target} cotired ${_excludedStr}.") + else() + set (_targetMsg "${_languagesStr} target ${_target} cotired.") + endif() + endif() + set (${_targetMsgVar} "${_targetMsg}" PARENT_SCOPE) +endfunction() + +function (cotire_choose_target_languages _target _targetLanguagesVar _wholeTargetVar) + set (_languages ${ARGN}) + set (_allSourceFiles "") + set (_allExcludedSourceFiles "") + set (_allCotiredSourceFiles "") + set (_targetLanguages "") + set (_pchEligibleTargetLanguages "") + get_target_property(_targetType ${_target} TYPE) + get_target_property(_targetSourceFiles ${_target} SOURCES) + get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) + get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) + set (_disableMsg "") + foreach (_language ${_languages}) + get_target_property(_prefixHeader ${_target} COTIRE_${_language}_PREFIX_HEADER) + get_target_property(_unityBuildFile ${_target} COTIRE_${_language}_UNITY_SOURCE) + if (_prefixHeader OR _unityBuildFile) + message (STATUS "cotire: target ${_target} has already been cotired.") + set (${_targetLanguagesVar} "" PARENT_SCOPE) + return() + endif() + if (_targetUsePCH AND "${_language}" MATCHES "^C|CXX$" AND DEFINED CMAKE_${_language}_COMPILER_ID) + if (CMAKE_${_language}_COMPILER_ID) + cotire_check_precompiled_header_support("${_language}" "${_target}" _disableMsg) + if (_disableMsg) + set (_targetUsePCH FALSE) + endif() + endif() + endif() + set (_sourceFiles "") + set (_excludedSources "") + set (_cotiredSources "") + cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) + if (_sourceFiles OR _excludedSources OR _cotiredSources) + list (APPEND _targetLanguages ${_language}) + endif() + if (_sourceFiles) + list (APPEND _allSourceFiles ${_sourceFiles}) + endif() + list (LENGTH _sourceFiles _numberOfSources) + if (NOT _numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) + list (APPEND _pchEligibleTargetLanguages ${_language}) + endif() + if (_excludedSources) + list (APPEND _allExcludedSourceFiles ${_excludedSources}) + endif() + if (_cotiredSources) + list (APPEND _allCotiredSourceFiles ${_cotiredSources}) + endif() + endforeach() + set (_targetMsgLevel STATUS) + if (NOT _targetLanguages) + string (REPLACE ";" " or " _languagesStr "${_languages}") + set (_disableMsg "No ${_languagesStr} source files.") + set (_targetUsePCH FALSE) + set (_targetAddSCU FALSE) + endif() + if (_targetUsePCH) + if (_allCotiredSourceFiles) + cotire_get_source_file_property_values(_cotireTargets COTIRE_TARGET ${_allCotiredSourceFiles}) + list (REMOVE_DUPLICATES _cotireTargets) + string (REPLACE ";" ", " _cotireTargetsStr "${_cotireTargets}") + set (_disableMsg "Target sources already include a precompiled header for target(s) ${_cotireTargets}.") + set (_disableMsg "${_disableMsg} Set target property COTIRE_ENABLE_PRECOMPILED_HEADER to FALSE for targets ${_target},") + set (_disableMsg "${_disableMsg} ${_cotireTargetsStr} to get a workable build system.") + set (_targetMsgLevel SEND_ERROR) + set (_targetUsePCH FALSE) + elseif (NOT _pchEligibleTargetLanguages) + set (_disableMsg "Too few applicable sources.") + set (_targetUsePCH FALSE) + elseif (XCODE AND _allExcludedSourceFiles) + # for Xcode, we cannot apply the precompiled header to individual sources, only to the whole target + set (_disableMsg "Exclusion of source files not supported for generator Xcode.") + set (_targetUsePCH FALSE) + elseif (XCODE AND "${_targetType}" STREQUAL "OBJECT_LIBRARY") + # for Xcode, we cannot apply the required PRE_BUILD action to generate the prefix header to an OBJECT_LIBRARY target + set (_disableMsg "Required PRE_BUILD action not supported for OBJECT_LIBRARY targets for generator Xcode.") + set (_targetUsePCH FALSE) + endif() + endif() + set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER ${_targetUsePCH}) + set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD ${_targetAddSCU}) + cotire_make_target_message(${_target} "${_targetLanguages}" "${_disableMsg}" _targetMsg ${_allExcludedSourceFiles}) + if (_targetMsg) + if (NOT DEFINED COTIREMSG_${_target}) + set (COTIREMSG_${_target} "") + endif() + if (COTIRE_VERBOSE OR NOT "${_targetMsgLevel}" STREQUAL "STATUS" OR + NOT "${COTIREMSG_${_target}}" STREQUAL "${_targetMsg}") + # cache message to avoid redundant messages on re-configure + set (COTIREMSG_${_target} "${_targetMsg}" CACHE INTERNAL "${_target} cotire message.") + message (${_targetMsgLevel} "${_targetMsg}") + endif() + endif() + list (LENGTH _targetLanguages _numberOfLanguages) + if (_numberOfLanguages GREATER 1 OR _allExcludedSourceFiles) + set (${_wholeTargetVar} FALSE PARENT_SCOPE) + else() + set (${_wholeTargetVar} TRUE PARENT_SCOPE) + endif() + set (${_targetLanguagesVar} ${_targetLanguages} PARENT_SCOPE) +endfunction() + +function (cotire_compute_unity_max_number_of_includes _target _maxIncludesVar) + set (_sourceFiles ${ARGN}) + get_target_property(_maxIncludes ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) + if (_maxIncludes MATCHES "(-j|--parallel|--jobs) ?([0-9]*)") + set (_numberOfThreads "${CMAKE_MATCH_2}") + if (NOT _numberOfThreads) + # use all available cores + ProcessorCount(_numberOfThreads) + endif() + list (LENGTH _sourceFiles _numberOfSources) + math (EXPR _maxIncludes "(${_numberOfSources} + ${_numberOfThreads} - 1) / ${_numberOfThreads}") + elseif (NOT _maxIncludes MATCHES "[0-9]+") + set (_maxIncludes 0) + endif() + if (COTIRE_DEBUG) + message (STATUS "${_target} unity source max includes: ${_maxIncludes}") + endif() + set (${_maxIncludesVar} ${_maxIncludes} PARENT_SCOPE) +endfunction() + +function (cotire_process_target_language _language _configurations _target _wholeTarget _cmdsVar) + set (${_cmdsVar} "" PARENT_SCOPE) + get_target_property(_targetSourceFiles ${_target} SOURCES) + set (_sourceFiles "") + set (_excludedSources "") + set (_cotiredSources "") + cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) + if (NOT _sourceFiles AND NOT _cotiredSources) + return() + endif() + set (_cmds "") + # check for user provided unity source file list + get_property(_unitySourceFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE_INIT) + if (NOT _unitySourceFiles) + set (_unitySourceFiles ${_sourceFiles} ${_cotiredSources}) + endif() + cotire_generate_target_script( + ${_language} "${_configurations}" ${_target} _targetScript _targetConfigScript ${_unitySourceFiles}) + # set up unity files for parallel compilation + cotire_compute_unity_max_number_of_includes(${_target} _maxIncludes ${_unitySourceFiles}) + cotire_make_unity_source_file_paths(${_language} ${_target} ${_maxIncludes} _unityFiles ${_unitySourceFiles}) + list (LENGTH _unityFiles _numberOfUnityFiles) + if (_numberOfUnityFiles EQUAL 0) + return() + elseif (_numberOfUnityFiles GREATER 1) + cotire_setup_unity_generation_commands( + ${_language} ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFiles}" _cmds ${_unitySourceFiles}) + endif() + # set up single unity file for prefix header generation + cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile) + cotire_setup_unity_generation_commands( + ${_language} ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFile}" _cmds ${_unitySourceFiles}) + cotire_make_prefix_file_path(${_language} ${_target} _prefixFile) + # set up prefix header + if (_prefixFile) + # check for user provided prefix header files + get_property(_prefixHeaderFiles TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT) + if (_prefixHeaderFiles) + cotire_setup_prefix_generation_from_provided_command( + ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" _cmds ${_prefixHeaderFiles}) + else() + cotire_setup_prefix_generation_from_unity_command( + ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" "${_unityFile}" _cmds ${_unitySourceFiles}) + endif() + # check if selected language has enough sources at all + list (LENGTH _sourceFiles _numberOfSources) + if (_numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) + set (_targetUsePCH FALSE) + else() + get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) + endif() + if (_targetUsePCH) + cotire_make_pch_file_path(${_language} ${_target} _pchFile) + if (_pchFile) + # first file in _sourceFiles is passed as the host file + cotire_setup_pch_file_compilation( + ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" "${_pchFile}" ${_sourceFiles}) + cotire_setup_pch_file_inclusion( + ${_language} ${_target} ${_wholeTarget} "${_prefixFile}" "${_pchFile}" ${_sourceFiles}) + endif() + elseif (_prefixHeaderFiles) + # user provided prefix header must be included unconditionally + cotire_setup_prefix_file_inclusion(${_language} ${_target} "${_prefixFile}" ${_sourceFiles}) + endif() + endif() + # mark target as cotired for language + set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE "${_unityFiles}") + if (_prefixFile) + set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER "${_prefixFile}") + if (_targetUsePCH AND _pchFile) + set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER "${_pchFile}") + endif() + endif() + set (${_cmdsVar} ${_cmds} PARENT_SCOPE) +endfunction() + +function (cotire_setup_clean_target _target) + set (_cleanTargetName "${_target}${COTIRE_CLEAN_TARGET_SUFFIX}") + if (NOT TARGET "${_cleanTargetName}") + cotire_set_cmd_to_prologue(_cmds) + get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" ABSOLUTE) + list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${_outputDir}" "${COTIRE_INTDIR}" "${_target}") + add_custom_target(${_cleanTargetName} + COMMAND ${_cmds} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + COMMENT "Cleaning up target ${_target} cotire generated files" + VERBATIM) + cotire_init_target("${_cleanTargetName}") + endif() +endfunction() + +function (cotire_setup_pch_target _languages _configurations _target) + if ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") + # for makefile based generators, we add a custom target to trigger the generation of the cotire related files + set (_dependsFiles "") + foreach (_language ${_languages}) + set (_props COTIRE_${_language}_PREFIX_HEADER COTIRE_${_language}_UNITY_SOURCE) + if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") + # Visual Studio and Intel only create precompiled header as a side effect + list (INSERT _props 0 COTIRE_${_language}_PRECOMPILED_HEADER) + endif() + cotire_get_first_set_property_value(_dependsFile TARGET ${_target} ${_props}) + if (_dependsFile) + list (APPEND _dependsFiles "${_dependsFile}") + endif() + endforeach() + if (_dependsFiles) + set (_pchTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}") + add_custom_target("${_pchTargetName}" DEPENDS ${_dependsFiles}) + cotire_init_target("${_pchTargetName}") + cotire_add_to_pch_all_target(${_pchTargetName}) + endif() + else() + # for other generators, we add the "clean all" target to clean up the precompiled header + cotire_setup_clean_all_target() + endif() +endfunction() + +function (cotire_filter_object_libraries _target _objectLibrariesVar) + set (_objectLibraries "") + foreach (_source ${ARGN}) + if (_source MATCHES "^\\$$") + list (APPEND _objectLibraries "${_source}") + endif() + endforeach() + set (${_objectLibrariesVar} ${_objectLibraries} PARENT_SCOPE) +endfunction() + +function (cotire_collect_unity_target_sources _target _languages _unityTargetSourcesVar) + get_target_property(_targetSourceFiles ${_target} SOURCES) + set (_unityTargetSources ${_targetSourceFiles}) + foreach (_language ${_languages}) + get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE) + if (_unityFiles) + # remove source files that are included in the unity source + set (_sourceFiles "") + set (_excludedSources "") + set (_cotiredSources "") + cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) + if (_sourceFiles OR _cotiredSources) + list (REMOVE_ITEM _unityTargetSources ${_sourceFiles} ${_cotiredSources}) + endif() + # add unity source files instead + list (APPEND _unityTargetSources ${_unityFiles}) + endif() + endforeach() + get_target_property(_linkLibrariesStrategy ${_target} COTIRE_UNITY_LINK_LIBRARIES_INIT) + if ("${_linkLibrariesStrategy}" MATCHES "^COPY_UNITY$") + cotire_filter_object_libraries(${_target} _objectLibraries ${_targetSourceFiles}) + if (_objectLibraries) + cotire_map_libraries("${_linkLibrariesStrategy}" _unityObjectLibraries ${_objectLibraries}) + list (REMOVE_ITEM _unityTargetSources ${_objectLibraries}) + list (APPEND _unityTargetSources ${_unityObjectLibraries}) + endif() + endif() + set (${_unityTargetSourcesVar} ${_unityTargetSources} PARENT_SCOPE) +endfunction() + +function (cotire_setup_unity_target_pch_usage _languages _target) + foreach (_language ${_languages}) + get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE) + if (_unityFiles) + get_property(_userPrefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT) + get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) + if (_userPrefixFile AND _prefixFile) + # user provided prefix header must be included unconditionally by unity sources + cotire_setup_prefix_file_inclusion(${_language} ${_target} "${_prefixFile}" ${_unityFiles}) + endif() + endif() + endforeach() +endfunction() + +function (cotire_setup_unity_build_target _languages _configurations _target) + get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME) + if (NOT _unityTargetName) + set (_unityTargetName "${_target}${COTIRE_UNITY_BUILD_TARGET_SUFFIX}") + endif() + # determine unity target sub type + get_target_property(_targetType ${_target} TYPE) + if ("${_targetType}" STREQUAL "EXECUTABLE") + set (_unityTargetSubType "") + elseif (_targetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY") + set (_unityTargetSubType "${CMAKE_MATCH_1}") + else() + message (WARNING "cotire: target ${_target} has unknown target type ${_targetType}.") + return() + endif() + # determine unity target sources + set (_unityTargetSources "") + cotire_collect_unity_target_sources(${_target} "${_languages}" _unityTargetSources) + # handle automatic Qt processing + get_target_property(_targetAutoMoc ${_target} AUTOMOC) + get_target_property(_targetAutoUic ${_target} AUTOUIC) + get_target_property(_targetAutoRcc ${_target} AUTORCC) + if (_targetAutoMoc OR _targetAutoUic OR _targetAutoRcc) + # if the original target sources are subject to CMake's automatic Qt processing, + # also include implicitly generated _automoc.cpp file + if (CMAKE_VERSION VERSION_LESS "3.8.0") + list (APPEND _unityTargetSources "${_target}_automoc.cpp") + set_property (SOURCE "${_target}_automoc.cpp" PROPERTY GENERATED TRUE) + else() + list (APPEND _unityTargetSources "${_target}_autogen/moc_compilation.cpp") + set_property (SOURCE "${_target}_autogen/moc_compilation.cpp" PROPERTY GENERATED TRUE) + endif() + endif() + # prevent AUTOMOC, AUTOUIC and AUTORCC properties from being set when the unity target is created + set (CMAKE_AUTOMOC OFF) + set (CMAKE_AUTOUIC OFF) + set (CMAKE_AUTORCC OFF) + if (COTIRE_DEBUG) + message (STATUS "add target ${_targetType} ${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}") + endif() + # generate unity target + if ("${_targetType}" STREQUAL "EXECUTABLE") + add_executable(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}) + else() + add_library(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}) + endif() + if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio") + # depend on original target's automoc target, if it exists + if (TARGET ${_target}_automoc) + add_dependencies(${_unityTargetName} ${_target}_automoc) + endif() + else() + if (_targetAutoMoc OR _targetAutoUic OR _targetAutoRcc) + # depend on the original target's implicity generated _automoc target + if (CMAKE_VERSION VERSION_LESS "3.8.0") + add_dependencies(${_unityTargetName} ${_target}_automoc) + else() + add_dependencies(${_unityTargetName} ${_target}_autogen) + endif() + endif() + endif() + # copy output location properties + set (_outputDirProperties + ARCHIVE_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY_ + LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_ + RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_) + if (COTIRE_UNITY_OUTPUT_DIRECTORY) + set (_setDefaultOutputDir TRUE) + if (IS_ABSOLUTE "${COTIRE_UNITY_OUTPUT_DIRECTORY}") + set (_outputDir "${COTIRE_UNITY_OUTPUT_DIRECTORY}") + else() + # append relative COTIRE_UNITY_OUTPUT_DIRECTORY to target's actual output directory + cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties}) + cotire_resolve_config_properties("${_configurations}" _properties ${_outputDirProperties}) + foreach (_property ${_properties}) + get_property(_outputDir TARGET ${_target} PROPERTY ${_property}) + if (_outputDir) + get_filename_component(_outputDir "${_outputDir}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE) + set_property(TARGET ${_unityTargetName} PROPERTY ${_property} "${_outputDir}") + set (_setDefaultOutputDir FALSE) + endif() + endforeach() + if (_setDefaultOutputDir) + get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE) + endif() + endif() + if (_setDefaultOutputDir) + set_target_properties(${_unityTargetName} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${_outputDir}" + LIBRARY_OUTPUT_DIRECTORY "${_outputDir}" + RUNTIME_OUTPUT_DIRECTORY "${_outputDir}") + endif() + else() + cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName} + ${_outputDirProperties}) + endif() + # copy output name + cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName} + ARCHIVE_OUTPUT_NAME ARCHIVE_OUTPUT_NAME_ + LIBRARY_OUTPUT_NAME LIBRARY_OUTPUT_NAME_ + OUTPUT_NAME OUTPUT_NAME_ + RUNTIME_OUTPUT_NAME RUNTIME_OUTPUT_NAME_ + PREFIX _POSTFIX SUFFIX + IMPORT_PREFIX IMPORT_SUFFIX) + # copy compile stuff + cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName} + COMPILE_DEFINITIONS COMPILE_DEFINITIONS_ + COMPILE_FLAGS COMPILE_OPTIONS + Fortran_FORMAT Fortran_MODULE_DIRECTORY + INCLUDE_DIRECTORIES + INTERPROCEDURAL_OPTIMIZATION INTERPROCEDURAL_OPTIMIZATION_ + POSITION_INDEPENDENT_CODE + C_COMPILER_LAUNCHER CXX_COMPILER_LAUNCHER + C_INCLUDE_WHAT_YOU_USE CXX_INCLUDE_WHAT_YOU_USE + C_VISIBILITY_PRESET CXX_VISIBILITY_PRESET VISIBILITY_INLINES_HIDDEN + C_CLANG_TIDY CXX_CLANG_TIDY) + # copy compile features + cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName} + C_EXTENSIONS C_STANDARD C_STANDARD_REQUIRED + CXX_EXTENSIONS CXX_STANDARD CXX_STANDARD_REQUIRED + COMPILE_FEATURES) + # copy interface stuff + cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName} + COMPATIBLE_INTERFACE_BOOL COMPATIBLE_INTERFACE_NUMBER_MAX COMPATIBLE_INTERFACE_NUMBER_MIN + COMPATIBLE_INTERFACE_STRING + INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_FEATURES INTERFACE_COMPILE_OPTIONS + INTERFACE_INCLUDE_DIRECTORIES INTERFACE_SOURCES + INTERFACE_POSITION_INDEPENDENT_CODE INTERFACE_SYSTEM_INCLUDE_DIRECTORIES + INTERFACE_AUTOUIC_OPTIONS NO_SYSTEM_FROM_IMPORTED) + # copy link stuff + cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName} + BUILD_WITH_INSTALL_RPATH INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH SKIP_BUILD_RPATH + LINKER_LANGUAGE LINK_DEPENDS LINK_DEPENDS_NO_SHARED + LINK_FLAGS LINK_FLAGS_ + LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_ + LINK_INTERFACE_MULTIPLICITY LINK_INTERFACE_MULTIPLICITY_ + LINK_SEARCH_START_STATIC LINK_SEARCH_END_STATIC + STATIC_LIBRARY_FLAGS STATIC_LIBRARY_FLAGS_ + NO_SONAME SOVERSION VERSION + LINK_WHAT_YOU_USE BUILD_RPATH) + # copy cmake stuff + cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName} + IMPLICIT_DEPENDS_INCLUDE_TRANSFORM RULE_LAUNCH_COMPILE RULE_LAUNCH_CUSTOM RULE_LAUNCH_LINK) + # copy Apple platform specific stuff + cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName} + BUNDLE BUNDLE_EXTENSION FRAMEWORK FRAMEWORK_VERSION INSTALL_NAME_DIR + MACOSX_BUNDLE MACOSX_BUNDLE_INFO_PLIST MACOSX_FRAMEWORK_INFO_PLIST MACOSX_RPATH + OSX_ARCHITECTURES OSX_ARCHITECTURES_ PRIVATE_HEADER PUBLIC_HEADER RESOURCE XCTEST + IOS_INSTALL_COMBINED XCODE_EXPLICIT_FILE_TYPE XCODE_PRODUCT_TYPE) + # copy Windows platform specific stuff + cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName} + GNUtoMS + COMPILE_PDB_NAME COMPILE_PDB_NAME_ + COMPILE_PDB_OUTPUT_DIRECTORY COMPILE_PDB_OUTPUT_DIRECTORY_ + PDB_NAME PDB_NAME_ PDB_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY_ + VS_DESKTOP_EXTENSIONS_VERSION VS_DOTNET_REFERENCES VS_DOTNET_TARGET_FRAMEWORK_VERSION + VS_GLOBAL_KEYWORD VS_GLOBAL_PROJECT_TYPES VS_GLOBAL_ROOTNAMESPACE + VS_IOT_EXTENSIONS_VERSION VS_IOT_STARTUP_TASK + VS_KEYWORD VS_MOBILE_EXTENSIONS_VERSION + VS_SCC_AUXPATH VS_SCC_LOCALPATH VS_SCC_PROJECTNAME VS_SCC_PROVIDER + VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION + VS_WINRT_COMPONENT VS_WINRT_EXTENSIONS VS_WINRT_REFERENCES + WIN32_EXECUTABLE WINDOWS_EXPORT_ALL_SYMBOLS + DEPLOYMENT_REMOTE_DIRECTORY VS_CONFIGURATION_TYPE + VS_SDK_REFERENCES VS_USER_PROPS VS_DEBUGGER_WORKING_DIRECTORY) + # copy Android platform specific stuff + cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName} + ANDROID_API ANDROID_API_MIN ANDROID_GUI + ANDROID_ANT_ADDITIONAL_OPTIONS ANDROID_ARCH ANDROID_ASSETS_DIRECTORIES + ANDROID_JAR_DEPENDENCIES ANDROID_JAR_DIRECTORIES ANDROID_JAVA_SOURCE_DIR + ANDROID_NATIVE_LIB_DEPENDENCIES ANDROID_NATIVE_LIB_DIRECTORIES + ANDROID_PROCESS_MAX ANDROID_PROGUARD ANDROID_PROGUARD_CONFIG_PATH + ANDROID_SECURE_PROPS_PATH ANDROID_SKIP_ANT_STEP ANDROID_STL_TYPE) + # use output name from original target + get_target_property(_targetOutputName ${_unityTargetName} OUTPUT_NAME) + if (NOT _targetOutputName) + set_property(TARGET ${_unityTargetName} PROPERTY OUTPUT_NAME "${_target}") + endif() + # use export symbol from original target + cotire_get_target_export_symbol("${_target}" _defineSymbol) + if (_defineSymbol) + set_property(TARGET ${_unityTargetName} PROPERTY DEFINE_SYMBOL "${_defineSymbol}") + if ("${_targetType}" STREQUAL "EXECUTABLE") + set_property(TARGET ${_unityTargetName} PROPERTY ENABLE_EXPORTS TRUE) + endif() + endif() + cotire_init_target(${_unityTargetName}) + cotire_add_to_unity_all_target(${_unityTargetName}) + set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_TARGET_NAME "${_unityTargetName}") +endfunction(cotire_setup_unity_build_target) + +function (cotire_target _target) + set(_options "") + set(_oneValueArgs "") + set(_multiValueArgs LANGUAGES CONFIGURATIONS) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if (NOT _option_LANGUAGES) + get_property (_option_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + endif() + if (NOT _option_CONFIGURATIONS) + cotire_get_configuration_types(_option_CONFIGURATIONS) + endif() + # check if cotire can be applied to target at all + cotire_is_target_supported(${_target} _isSupported) + if (NOT _isSupported) + get_target_property(_imported ${_target} IMPORTED) + get_target_property(_targetType ${_target} TYPE) + if (_imported) + message (WARNING "cotire: imported ${_targetType} target ${_target} cannot be cotired.") + else() + message (STATUS "cotire: ${_targetType} target ${_target} cannot be cotired.") + endif() + return() + endif() + # resolve alias + get_target_property(_aliasName ${_target} ALIASED_TARGET) + if (_aliasName) + if (COTIRE_DEBUG) + message (STATUS "${_target} is an alias. Applying cotire to aliased target ${_aliasName} instead.") + endif() + set (_target ${_aliasName}) + endif() + # check if target needs to be cotired for build type + # when using configuration types, the test is performed at build time + cotire_init_cotire_target_properties(${_target}) + if (NOT CMAKE_CONFIGURATION_TYPES) + if (CMAKE_BUILD_TYPE) + list (FIND _option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}" _index) + else() + list (FIND _option_CONFIGURATIONS "None" _index) + endif() + if (_index EQUAL -1) + if (COTIRE_DEBUG) + message (STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} not cotired (${_option_CONFIGURATIONS})") + endif() + return() + endif() + endif() + # when not using configuration types, immediately create cotire intermediate dir + if (NOT CMAKE_CONFIGURATION_TYPES) + cotire_get_intermediate_dir(_baseDir) + file (MAKE_DIRECTORY "${_baseDir}") + endif() + # choose languages that apply to the target + cotire_choose_target_languages("${_target}" _targetLanguages _wholeTarget ${_option_LANGUAGES}) + if (NOT _targetLanguages) + return() + endif() + set (_cmds "") + foreach (_language ${_targetLanguages}) + cotire_process_target_language("${_language}" "${_option_CONFIGURATIONS}" ${_target} ${_wholeTarget} _cmd) + if (_cmd) + list (APPEND _cmds ${_cmd}) + endif() + endforeach() + get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) + if (_targetAddSCU) + cotire_setup_unity_build_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target}) + endif() + get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) + if (_targetUsePCH) + cotire_setup_target_pch_usage("${_targetLanguages}" ${_target} ${_wholeTarget} ${_cmds}) + cotire_setup_pch_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target}) + if (_targetAddSCU) + cotire_setup_unity_target_pch_usage("${_targetLanguages}" ${_target}) + endif() + endif() + get_target_property(_targetAddCleanTarget ${_target} COTIRE_ADD_CLEAN) + if (_targetAddCleanTarget) + cotire_setup_clean_target(${_target}) + endif() +endfunction(cotire_target) + +function (cotire_map_libraries _strategy _mappedLibrariesVar) + set (_mappedLibraries "") + foreach (_library ${ARGN}) + if (_library MATCHES "^\\$$") + set (_libraryName "${CMAKE_MATCH_1}") + set (_linkOnly TRUE) + set (_objectLibrary FALSE) + elseif (_library MATCHES "^\\$$") + set (_libraryName "${CMAKE_MATCH_1}") + set (_linkOnly FALSE) + set (_objectLibrary TRUE) + else() + set (_libraryName "${_library}") + set (_linkOnly FALSE) + set (_objectLibrary FALSE) + endif() + if ("${_strategy}" MATCHES "COPY_UNITY") + cotire_is_target_supported(${_libraryName} _isSupported) + if (_isSupported) + # use target's corresponding unity target, if available + get_target_property(_libraryUnityTargetName ${_libraryName} COTIRE_UNITY_TARGET_NAME) + if (TARGET "${_libraryUnityTargetName}") + if (_linkOnly) + list (APPEND _mappedLibraries "$") + elseif (_objectLibrary) + list (APPEND _mappedLibraries "$") + else() + list (APPEND _mappedLibraries "${_libraryUnityTargetName}") + endif() + else() + list (APPEND _mappedLibraries "${_library}") + endif() + else() + list (APPEND _mappedLibraries "${_library}") + endif() + else() + list (APPEND _mappedLibraries "${_library}") + endif() + endforeach() + list (REMOVE_DUPLICATES _mappedLibraries) + set (${_mappedLibrariesVar} ${_mappedLibraries} PARENT_SCOPE) +endfunction() + +function (cotire_target_link_libraries _target) + cotire_is_target_supported(${_target} _isSupported) + if (NOT _isSupported) + return() + endif() + get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME) + if (TARGET "${_unityTargetName}") + get_target_property(_linkLibrariesStrategy ${_target} COTIRE_UNITY_LINK_LIBRARIES_INIT) + if (COTIRE_DEBUG) + message (STATUS "unity target ${_unityTargetName} link strategy: ${_linkLibrariesStrategy}") + endif() + if ("${_linkLibrariesStrategy}" MATCHES "^(COPY|COPY_UNITY)$") + get_target_property(_linkLibraries ${_target} LINK_LIBRARIES) + if (_linkLibraries) + cotire_map_libraries("${_linkLibrariesStrategy}" _unityLinkLibraries ${_linkLibraries}) + set_target_properties(${_unityTargetName} PROPERTIES LINK_LIBRARIES "${_unityLinkLibraries}") + if (COTIRE_DEBUG) + message (STATUS "unity target ${_unityTargetName} link libraries: ${_unityLinkLibraries}") + endif() + endif() + get_target_property(_interfaceLinkLibraries ${_target} INTERFACE_LINK_LIBRARIES) + if (_interfaceLinkLibraries) + cotire_map_libraries("${_linkLibrariesStrategy}" _unityLinkInterfaceLibraries ${_interfaceLinkLibraries}) + set_target_properties(${_unityTargetName} PROPERTIES INTERFACE_LINK_LIBRARIES "${_unityLinkInterfaceLibraries}") + if (COTIRE_DEBUG) + message (STATUS "unity target ${_unityTargetName} interface link libraries: ${_unityLinkInterfaceLibraries}") + endif() + endif() + endif() + endif() +endfunction(cotire_target_link_libraries) + +function (cotire_cleanup _binaryDir _cotireIntermediateDirName _targetName) + if (_targetName) + file (GLOB_RECURSE _cotireFiles "${_binaryDir}/${_targetName}*.*") + else() + file (GLOB_RECURSE _cotireFiles "${_binaryDir}/*.*") + endif() + # filter files in intermediate directory + set (_filesToRemove "") + foreach (_file ${_cotireFiles}) + get_filename_component(_dir "${_file}" DIRECTORY) + get_filename_component(_dirName "${_dir}" NAME) + if ("${_dirName}" STREQUAL "${_cotireIntermediateDirName}") + list (APPEND _filesToRemove "${_file}") + endif() + endforeach() + if (_filesToRemove) + if (COTIRE_VERBOSE) + message (STATUS "cleaning up ${_filesToRemove}") + endif() + file (REMOVE ${_filesToRemove}) + endif() +endfunction() + +function (cotire_init_target _targetName) + if (COTIRE_TARGETS_FOLDER) + set_target_properties(${_targetName} PROPERTIES FOLDER "${COTIRE_TARGETS_FOLDER}") + endif() + set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_ALL TRUE) + if (MSVC_IDE) + set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE) + endif() +endfunction() + +function (cotire_add_to_pch_all_target _pchTargetName) + set (_targetName "${COTIRE_PCH_ALL_TARGET_NAME}") + if (NOT TARGET "${_targetName}") + add_custom_target("${_targetName}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + VERBATIM) + cotire_init_target("${_targetName}") + endif() + cotire_setup_clean_all_target() + add_dependencies(${_targetName} ${_pchTargetName}) +endfunction() + +function (cotire_add_to_unity_all_target _unityTargetName) + set (_targetName "${COTIRE_UNITY_BUILD_ALL_TARGET_NAME}") + if (NOT TARGET "${_targetName}") + add_custom_target("${_targetName}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + VERBATIM) + cotire_init_target("${_targetName}") + endif() + cotire_setup_clean_all_target() + add_dependencies(${_targetName} ${_unityTargetName}) +endfunction() + +function (cotire_setup_clean_all_target) + set (_targetName "${COTIRE_CLEAN_ALL_TARGET_NAME}") + if (NOT TARGET "${_targetName}") + cotire_set_cmd_to_prologue(_cmds) + list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${CMAKE_BINARY_DIR}" "${COTIRE_INTDIR}") + add_custom_target(${_targetName} + COMMAND ${_cmds} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + COMMENT "Cleaning up all cotire generated files" + VERBATIM) + cotire_init_target("${_targetName}") + endif() +endfunction() + +function (cotire) + set(_options "") + set(_oneValueArgs "") + set(_multiValueArgs LANGUAGES CONFIGURATIONS) + cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + set (_targets ${_option_UNPARSED_ARGUMENTS}) + foreach (_target ${_targets}) + if (TARGET ${_target}) + cotire_target(${_target} LANGUAGES ${_option_LANGUAGES} CONFIGURATIONS ${_option_CONFIGURATIONS}) + else() + message (WARNING "cotire: ${_target} is not a target.") + endif() + endforeach() + foreach (_target ${_targets}) + if (TARGET ${_target}) + cotire_target_link_libraries(${_target}) + endif() + endforeach() +endfunction() + +if (CMAKE_SCRIPT_MODE_FILE) + + # cotire is being run in script mode + # locate -P on command args + set (COTIRE_ARGC -1) + foreach (_index RANGE ${CMAKE_ARGC}) + if (COTIRE_ARGC GREATER -1) + set (COTIRE_ARGV${COTIRE_ARGC} "${CMAKE_ARGV${_index}}") + math (EXPR COTIRE_ARGC "${COTIRE_ARGC} + 1") + elseif ("${CMAKE_ARGV${_index}}" STREQUAL "-P") + set (COTIRE_ARGC 0) + endif() + endforeach() + + # include target script if available + if ("${COTIRE_ARGV2}" MATCHES "\\.cmake$") + # the included target scripts sets up additional variables relating to the target (e.g., COTIRE_TARGET_SOURCES) + include("${COTIRE_ARGV2}") + endif() + + if (COTIRE_DEBUG) + message (STATUS "${COTIRE_ARGV0} ${COTIRE_ARGV1} ${COTIRE_ARGV2} ${COTIRE_ARGV3} ${COTIRE_ARGV4} ${COTIRE_ARGV5}") + endif() + + if (NOT COTIRE_BUILD_TYPE) + set (COTIRE_BUILD_TYPE "None") + endif() + string (TOUPPER "${COTIRE_BUILD_TYPE}" _upperConfig) + set (_includeDirs ${COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig}}) + set (_systemIncludeDirs ${COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}}) + set (_compileDefinitions ${COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}}) + set (_compileFlags ${COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}}) + # check if target has been cotired for actual build type COTIRE_BUILD_TYPE + list (FIND COTIRE_TARGET_CONFIGURATION_TYPES "${COTIRE_BUILD_TYPE}" _index) + if (_index GREATER -1) + set (_sources ${COTIRE_TARGET_SOURCES}) + set (_sourcesDefinitions ${COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig}}) + else() + if (COTIRE_DEBUG) + message (STATUS "COTIRE_BUILD_TYPE=${COTIRE_BUILD_TYPE} not cotired (${COTIRE_TARGET_CONFIGURATION_TYPES})") + endif() + set (_sources "") + set (_sourcesDefinitions "") + endif() + set (_targetPreUndefs ${COTIRE_TARGET_PRE_UNDEFS}) + set (_targetPostUndefs ${COTIRE_TARGET_POST_UNDEFS}) + set (_sourcesPreUndefs ${COTIRE_TARGET_SOURCES_PRE_UNDEFS}) + set (_sourcesPostUndefs ${COTIRE_TARGET_SOURCES_POST_UNDEFS}) + + if ("${COTIRE_ARGV1}" STREQUAL "unity") + + if (XCODE) + # executing pre-build action under Xcode, check dependency on target script + set (_dependsOption DEPENDS "${COTIRE_ARGV2}") + else() + # executing custom command, no need to re-check for dependencies + set (_dependsOption "") + endif() + + cotire_select_unity_source_files("${COTIRE_ARGV3}" _sources ${_sources}) + + cotire_generate_unity_source( + "${COTIRE_ARGV3}" ${_sources} + LANGUAGE "${COTIRE_TARGET_LANGUAGE}" + SOURCES_COMPILE_DEFINITIONS ${_sourcesDefinitions} + PRE_UNDEFS ${_targetPreUndefs} + POST_UNDEFS ${_targetPostUndefs} + SOURCES_PRE_UNDEFS ${_sourcesPreUndefs} + SOURCES_POST_UNDEFS ${_sourcesPostUndefs} + ${_dependsOption}) + + elseif ("${COTIRE_ARGV1}" STREQUAL "prefix") + + if (XCODE) + # executing pre-build action under Xcode, check dependency on unity file and prefix dependencies + set (_dependsOption DEPENDS "${COTIRE_ARGV4}" ${COTIRE_TARGET_PREFIX_DEPENDS}) + else() + # executing custom command, no need to re-check for dependencies + set (_dependsOption "") + endif() + + set (_files "") + foreach (_index RANGE 4 ${COTIRE_ARGC}) + if (COTIRE_ARGV${_index}) + list (APPEND _files "${COTIRE_ARGV${_index}}") + endif() + endforeach() + + cotire_generate_prefix_header( + "${COTIRE_ARGV3}" ${_files} + COMPILER_LAUNCHER "${COTIRE_TARGET_${COTIRE_TARGET_LANGUAGE}_COMPILER_LAUNCHER}" + COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}" + COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1} + COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}" + COMPILER_VERSION "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}" + LANGUAGE "${COTIRE_TARGET_LANGUAGE}" + IGNORE_PATH "${COTIRE_TARGET_IGNORE_PATH};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH}" + INCLUDE_PATH ${COTIRE_TARGET_INCLUDE_PATH} + IGNORE_EXTENSIONS "${CMAKE_${COTIRE_TARGET_LANGUAGE}_SOURCE_FILE_EXTENSIONS};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS}" + INCLUDE_PRIORITY_PATH ${COTIRE_TARGET_INCLUDE_PRIORITY_PATH} + INCLUDE_DIRECTORIES ${_includeDirs} + SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs} + COMPILE_DEFINITIONS ${_compileDefinitions} + COMPILE_FLAGS ${_compileFlags} + ${_dependsOption}) + + elseif ("${COTIRE_ARGV1}" STREQUAL "precompile") + + set (_files "") + foreach (_index RANGE 5 ${COTIRE_ARGC}) + if (COTIRE_ARGV${_index}) + list (APPEND _files "${COTIRE_ARGV${_index}}") + endif() + endforeach() + + cotire_precompile_prefix_header( + "${COTIRE_ARGV3}" "${COTIRE_ARGV4}" "${COTIRE_ARGV5}" + COMPILER_LAUNCHER "${COTIRE_TARGET_${COTIRE_TARGET_LANGUAGE}_COMPILER_LAUNCHER}" + COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}" + COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1} + COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}" + COMPILER_VERSION "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}" + LANGUAGE "${COTIRE_TARGET_LANGUAGE}" + INCLUDE_DIRECTORIES ${_includeDirs} + SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs} + COMPILE_DEFINITIONS ${_compileDefinitions} + COMPILE_FLAGS ${_compileFlags}) + + elseif ("${COTIRE_ARGV1}" STREQUAL "combine") + + if (COTIRE_TARGET_LANGUAGE) + set (_combinedFile "${COTIRE_ARGV3}") + set (_startIndex 4) + else() + set (_combinedFile "${COTIRE_ARGV2}") + set (_startIndex 3) + endif() + set (_files "") + foreach (_index RANGE ${_startIndex} ${COTIRE_ARGC}) + if (COTIRE_ARGV${_index}) + list (APPEND _files "${COTIRE_ARGV${_index}}") + endif() + endforeach() + + if (XCODE) + # executing pre-build action under Xcode, check dependency on files to be combined + set (_dependsOption DEPENDS ${_files}) + else() + # executing custom command, no need to re-check for dependencies + set (_dependsOption "") + endif() + + if (COTIRE_TARGET_LANGUAGE) + cotire_generate_unity_source( + "${_combinedFile}" ${_files} + LANGUAGE "${COTIRE_TARGET_LANGUAGE}" + ${_dependsOption}) + else() + cotire_generate_unity_source("${_combinedFile}" ${_files} ${_dependsOption}) + endif() + + elseif ("${COTIRE_ARGV1}" STREQUAL "cleanup") + + cotire_cleanup("${COTIRE_ARGV2}" "${COTIRE_ARGV3}" "${COTIRE_ARGV4}") + + else() + message (FATAL_ERROR "cotire: unknown command \"${COTIRE_ARGV1}\".") + endif() + +else() + + # cotire is being run in include mode + # set up all variable and property definitions + + if (NOT DEFINED COTIRE_DEBUG_INIT) + if (DEFINED COTIRE_DEBUG) + set (COTIRE_DEBUG_INIT ${COTIRE_DEBUG}) + else() + set (COTIRE_DEBUG_INIT FALSE) + endif() + endif() + option (COTIRE_DEBUG "Enable cotire debugging output?" ${COTIRE_DEBUG_INIT}) + + if (NOT DEFINED COTIRE_VERBOSE_INIT) + if (DEFINED COTIRE_VERBOSE) + set (COTIRE_VERBOSE_INIT ${COTIRE_VERBOSE}) + else() + set (COTIRE_VERBOSE_INIT FALSE) + endif() + endif() + option (COTIRE_VERBOSE "Enable cotire verbose output?" ${COTIRE_VERBOSE_INIT}) + + set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS "inc;inl;ipp" CACHE STRING + "Ignore headers with the listed file extensions from the generated prefix header.") + + set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH "" CACHE STRING + "Ignore headers from these directories when generating the prefix header.") + + set (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS "m;mm" CACHE STRING + "Ignore sources with the listed file extensions from the generated unity source.") + + set (COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES "3" CACHE STRING + "Minimum number of sources in target required to enable use of precompiled header.") + + if (NOT DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT) + if (DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT ${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}) + elseif ("${CMAKE_GENERATOR}" MATCHES "JOM|Ninja|Visual Studio") + # enable parallelization for generators that run multiple jobs by default + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "-j") + else() + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "0") + endif() + endif() + set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT}" CACHE STRING + "Maximum number of source files to include in a single unity source file.") + + if (NOT COTIRE_PREFIX_HEADER_FILENAME_SUFFIX) + set (COTIRE_PREFIX_HEADER_FILENAME_SUFFIX "_prefix") + endif() + if (NOT COTIRE_UNITY_SOURCE_FILENAME_SUFFIX) + set (COTIRE_UNITY_SOURCE_FILENAME_SUFFIX "_unity") + endif() + if (NOT COTIRE_INTDIR) + set (COTIRE_INTDIR "cotire") + endif() + if (NOT COTIRE_PCH_ALL_TARGET_NAME) + set (COTIRE_PCH_ALL_TARGET_NAME "all_pch") + endif() + if (NOT COTIRE_UNITY_BUILD_ALL_TARGET_NAME) + set (COTIRE_UNITY_BUILD_ALL_TARGET_NAME "all_unity") + endif() + if (NOT COTIRE_CLEAN_ALL_TARGET_NAME) + set (COTIRE_CLEAN_ALL_TARGET_NAME "clean_cotire") + endif() + if (NOT COTIRE_CLEAN_TARGET_SUFFIX) + set (COTIRE_CLEAN_TARGET_SUFFIX "_clean_cotire") + endif() + if (NOT COTIRE_PCH_TARGET_SUFFIX) + set (COTIRE_PCH_TARGET_SUFFIX "_pch") + endif() + if (MSVC) + # MSVC default PCH memory scaling factor of 100 percent (75 MB) is too small for template heavy C++ code + # use a bigger default factor of 170 percent (128 MB) + if (NOT DEFINED COTIRE_PCH_MEMORY_SCALING_FACTOR) + set (COTIRE_PCH_MEMORY_SCALING_FACTOR "170") + endif() + endif() + if (NOT COTIRE_UNITY_BUILD_TARGET_SUFFIX) + set (COTIRE_UNITY_BUILD_TARGET_SUFFIX "_unity") + endif() + if (NOT DEFINED COTIRE_TARGETS_FOLDER) + set (COTIRE_TARGETS_FOLDER "cotire") + endif() + if (NOT DEFINED COTIRE_UNITY_OUTPUT_DIRECTORY) + if ("${CMAKE_GENERATOR}" MATCHES "Ninja") + # generated Ninja build files do not work if the unity target produces the same output file as the cotired target + set (COTIRE_UNITY_OUTPUT_DIRECTORY "unity") + else() + set (COTIRE_UNITY_OUTPUT_DIRECTORY "") + endif() + endif() + + # define cotire cache variables + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH" + BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." + FULL_DOCS + "The variable can be set to a semicolon separated list of include directories." + "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header." + "If not defined, defaults to empty list." + ) + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS" + BRIEF_DOCS "Ignore includes with the listed file extensions from the generated prefix header." + FULL_DOCS + "The variable can be set to a semicolon separated list of file extensions." + "If a header file extension matches one in the list, it will be excluded from the generated prefix header." + "Includes with an extension in CMAKE__SOURCE_FILE_EXTENSIONS are always ignored." + "If not defined, defaults to inc;inl;ipp." + ) + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS" + BRIEF_DOCS "Exclude sources with the listed file extensions from the generated unity source." + FULL_DOCS + "The variable can be set to a semicolon separated list of file extensions." + "If a source file extension matches one in the list, it will be excluded from the generated unity source file." + "Source files with an extension in CMAKE__IGNORE_EXTENSIONS are always excluded." + "If not defined, defaults to m;mm." + ) + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES" + BRIEF_DOCS "Minimum number of sources in target required to enable use of precompiled header." + FULL_DOCS + "The variable can be set to an integer > 0." + "If a target contains less than that number of source files, cotire will not enable the use of the precompiled header for the target." + "If not defined, defaults to 3." + ) + + define_property( + CACHED_VARIABLE PROPERTY "COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES" + BRIEF_DOCS "Maximum number of source files to include in a single unity source file." + FULL_DOCS + "This may be set to an integer >= 0." + "If 0, cotire will only create a single unity source file." + "If a target contains more than that number of source files, cotire will create multiple unity source files for it." + "Can be set to \"-j\" to optimize the count of unity source files for the number of available processor cores." + "Can be set to \"-j jobs\" to optimize the number of unity source files for the given number of simultaneous jobs." + "Is used to initialize the target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES." + "Defaults to \"-j\" for the generators Visual Studio, JOM or Ninja. Defaults to 0 otherwise." + ) + + # define cotire directory properties + + define_property( + DIRECTORY PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" + BRIEF_DOCS "Modify build command of cotired targets added in this directory to make use of the generated precompiled header." + FULL_DOCS + "See target property COTIRE_ENABLE_PRECOMPILED_HEADER." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_ADD_UNITY_BUILD" + BRIEF_DOCS "Add a new target that performs a unity build for cotired targets added in this directory." + FULL_DOCS + "See target property COTIRE_ADD_UNITY_BUILD." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_ADD_CLEAN" + BRIEF_DOCS "Add a new target that cleans all cotire generated files for cotired targets added in this directory." + FULL_DOCS + "See target property COTIRE_ADD_CLEAN." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" + BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." + FULL_DOCS + "See target property COTIRE_PREFIX_HEADER_IGNORE_PATH." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" + BRIEF_DOCS "Honor headers from these directories when generating the prefix header." + FULL_DOCS + "See target property COTIRE_PREFIX_HEADER_INCLUDE_PATH." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH" + BRIEF_DOCS "Header paths matching one of these directories are put at the top of the prefix header." + FULL_DOCS + "See target property COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each source file." + FULL_DOCS + "See target property COTIRE_UNITY_SOURCE_PRE_UNDEFS." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each source file." + FULL_DOCS + "See target property COTIRE_UNITY_SOURCE_POST_UNDEFS." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" + BRIEF_DOCS "Maximum number of source files to include in a single unity source file." + FULL_DOCS + "See target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES." + ) + + define_property( + DIRECTORY PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" + BRIEF_DOCS "Define strategy for setting up the unity target's link libraries." + FULL_DOCS + "See target property COTIRE_UNITY_LINK_LIBRARIES_INIT." + ) + + # define cotire target properties + + define_property( + TARGET PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" INHERITED + BRIEF_DOCS "Modify this target's build command to make use of the generated precompiled header." + FULL_DOCS + "If this property is set to TRUE, cotire will modify the build command to make use of the generated precompiled header." + "Irrespective of the value of this property, cotire will setup custom commands to generate the unity source and prefix header for the target." + "For makefile based generators cotire will also set up a custom target to manually invoke the generation of the precompiled header." + "The target name will be set to this target's name with the suffix _pch appended." + "Inherited from directory." + "Defaults to TRUE." + ) + + define_property( + TARGET PROPERTY "COTIRE_ADD_UNITY_BUILD" INHERITED + BRIEF_DOCS "Add a new target that performs a unity build for this target." + FULL_DOCS + "If this property is set to TRUE, cotire creates a new target of the same type that uses the generated unity source file instead of the target sources." + "Most of the relevant target properties will be copied from this target to the new unity build target." + "Target dependencies and linked libraries have to be manually set up for the new unity build target." + "The unity target name will be set to this target's name with the suffix _unity appended." + "Inherited from directory." + "Defaults to TRUE." + ) + + define_property( + TARGET PROPERTY "COTIRE_ADD_CLEAN" INHERITED + BRIEF_DOCS "Add a new target that cleans all cotire generated files for this target." + FULL_DOCS + "If this property is set to TRUE, cotire creates a new target that clean all files (unity source, prefix header, precompiled header)." + "The clean target name will be set to this target's name with the suffix _clean_cotire appended." + "Inherited from directory." + "Defaults to FALSE." + ) + + define_property( + TARGET PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" INHERITED + BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." + FULL_DOCS + "The property can be set to a list of directories." + "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header." + "Inherited from directory." + "If not set, this property is initialized to \${CMAKE_SOURCE_DIR};\${CMAKE_BINARY_DIR}." + ) + + define_property( + TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" INHERITED + BRIEF_DOCS "Honor headers from these directories when generating the prefix header." + FULL_DOCS + "The property can be set to a list of directories." + "If a header file is found in one of these directories or sub-directories, it will be included in the generated prefix header." + "If a header file is both selected by COTIRE_PREFIX_HEADER_IGNORE_PATH and COTIRE_PREFIX_HEADER_INCLUDE_PATH," + "the option which yields the closer relative path match wins." + "Inherited from directory." + "If not set, this property is initialized to the empty list." + ) + + define_property( + TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH" INHERITED + BRIEF_DOCS "Header paths matching one of these directories are put at the top of prefix header." + FULL_DOCS + "The property can be set to a list of directories." + "Header file paths matching one of these directories will be inserted at the beginning of the generated prefix header." + "Header files are sorted according to the order of the directories in the property." + "If not set, this property is initialized to the empty list." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" INHERITED + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each target source file." + FULL_DOCS + "This may be set to a semicolon-separated list of preprocessor symbols." + "cotire will add corresponding #undef directives to the generated unit source file before each target source file." + "Inherited from directory." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" INHERITED + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each target source file." + FULL_DOCS + "This may be set to a semicolon-separated list of preprocessor symbols." + "cotire will add corresponding #undef directives to the generated unit source file after each target source file." + "Inherited from directory." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" INHERITED + BRIEF_DOCS "Maximum number of source files to include in a single unity source file." + FULL_DOCS + "This may be set to an integer > 0." + "If a target contains more than that number of source files, cotire will create multiple unity build files for it." + "If not set, cotire will only create a single unity source file." + "Inherited from directory." + "Defaults to empty." + ) + + define_property( + TARGET PROPERTY "COTIRE__UNITY_SOURCE_INIT" + BRIEF_DOCS "User provided unity source file to be used instead of the automatically generated one." + FULL_DOCS + "If set, cotire will only add the given file(s) to the generated unity source file." + "If not set, cotire will add all the target source files to the generated unity source file." + "The property can be set to a user provided unity source file." + "Defaults to empty." + ) + + define_property( + TARGET PROPERTY "COTIRE__PREFIX_HEADER_INIT" + BRIEF_DOCS "User provided prefix header file to be used instead of the automatically generated one." + FULL_DOCS + "If set, cotire will add the given header file(s) to the generated prefix header file." + "If not set, cotire will generate a prefix header by tracking the header files included by the unity source file." + "The property can be set to a user provided prefix header file (e.g., stdafx.h)." + "Defaults to empty." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" INHERITED + BRIEF_DOCS "Define strategy for setting up unity target's link libraries." + FULL_DOCS + "If this property is empty or set to NONE, the generated unity target's link libraries have to be set up manually." + "If this property is set to COPY, the unity target's link libraries will be copied from this target." + "If this property is set to COPY_UNITY, the unity target's link libraries will be copied from this target with considering existing unity targets." + "Inherited from directory." + "Defaults to empty." + ) + + define_property( + TARGET PROPERTY "COTIRE__UNITY_SOURCE" + BRIEF_DOCS "Read-only property. The generated unity source file(s)." + FULL_DOCS + "cotire sets this property to the path of the generated single computation unit source file for the target." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE__PREFIX_HEADER" + BRIEF_DOCS "Read-only property. The generated prefix header file." + FULL_DOCS + "cotire sets this property to the full path of the generated language prefix header for the target." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE__PRECOMPILED_HEADER" + BRIEF_DOCS "Read-only property. The generated precompiled header file." + FULL_DOCS + "cotire sets this property to the full path of the generated language precompiled header binary for the target." + "Defaults to empty string." + ) + + define_property( + TARGET PROPERTY "COTIRE_UNITY_TARGET_NAME" + BRIEF_DOCS "The name of the generated unity build target corresponding to this target." + FULL_DOCS + "This property can be set to the desired name of the unity target that will be created by cotire." + "If not set, the unity target name will be set to this target's name with the suffix _unity appended." + "After this target has been processed by cotire, the property is set to the actual name of the generated unity target." + "Defaults to empty string." + ) + + # define cotire source properties + + define_property( + SOURCE PROPERTY "COTIRE_EXCLUDED" + BRIEF_DOCS "Do not modify source file's build command." + FULL_DOCS + "If this property is set to TRUE, the source file's build command will not be modified to make use of the precompiled header." + "The source file will also be excluded from the generated unity source file." + "Source files that have their COMPILE_FLAGS property set will be excluded by default." + "Defaults to FALSE." + ) + + define_property( + SOURCE PROPERTY "COTIRE_DEPENDENCY" + BRIEF_DOCS "Add this source file to dependencies of the automatically generated prefix header file." + FULL_DOCS + "If this property is set to TRUE, the source file is added to dependencies of the generated prefix header file." + "If the file is modified, cotire will re-generate the prefix header source upon build." + "Defaults to FALSE." + ) + + define_property( + SOURCE PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of this source file." + FULL_DOCS + "This may be set to a semicolon-separated list of preprocessor symbols." + "cotire will add corresponding #undef directives to the generated unit source file before this file is included." + "Defaults to empty string." + ) + + define_property( + SOURCE PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" + BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of this source file." + FULL_DOCS + "This may be set to a semicolon-separated list of preprocessor symbols." + "cotire will add corresponding #undef directives to the generated unit source file after this file is included." + "Defaults to empty string." + ) + + define_property( + SOURCE PROPERTY "COTIRE_START_NEW_UNITY_SOURCE" + BRIEF_DOCS "Start a new unity source file which includes this source file as the first one." + FULL_DOCS + "If this property is set to TRUE, cotire will complete the current unity file and start a new one." + "The new unity source file will include this source file as the first one." + "This property essentially works as a separator for unity source files." + "Defaults to FALSE." + ) + + define_property( + SOURCE PROPERTY "COTIRE_TARGET" + BRIEF_DOCS "Read-only property. Mark this source file as cotired for the given target." + FULL_DOCS + "cotire sets this property to the name of target, that the source file's build command has been altered for." + "Defaults to empty string." + ) + + message (STATUS "cotire ${COTIRE_CMAKE_MODULE_VERSION} loaded.") + +endif() \ No newline at end of file diff --git a/contrib/cmake/modules/ucm.cmake b/contrib/cmake/modules/ucm.cmake new file mode 100644 index 00000000..1b534dd1 --- /dev/null +++ b/contrib/cmake/modules/ucm.cmake @@ -0,0 +1,634 @@ +# +# ucm.cmake - useful cmake macros +# +# Copyright (c) 2016 Viktor Kirilov +# +# Distributed under the MIT Software License +# See accompanying file LICENSE.txt or copy at +# https://opensource.org/licenses/MIT +# +# The documentation can be found at the library's page: +# https://github.com/onqtam/ucm + +cmake_minimum_required(VERSION 2.8.12) + +include(CMakeParseArguments) + +# optionally include cotire - the git submodule might not be inited (or the user might have already included it) +if(NOT COMMAND cotire) + include(${CMAKE_CURRENT_LIST_DIR}/../cotire/CMake/cotire.cmake OPTIONAL) +endif() + +if(COMMAND cotire AND "1.7.9" VERSION_LESS "${COTIRE_CMAKE_MODULE_VERSION}") + set(ucm_with_cotire 1) +else() + set(ucm_with_cotire 0) +endif() + +option(UCM_UNITY_BUILD "Enable unity build for targets registered with the ucm_add_target() macro" OFF) +option(UCM_NO_COTIRE_FOLDER "Do not use a cotire folder in the solution explorer for all unity and cotire related targets" ON) + +# ucm_add_flags +# Adds compiler flags to CMAKE__FLAGS or to a specific config +macro(ucm_add_flags) + cmake_parse_arguments(ARG "C;CXX;CLEAR_OLD" "" "CONFIG" ${ARGN}) + + if(NOT ARG_CONFIG) + set(ARG_CONFIG " ") + endif() + + foreach(CONFIG ${ARG_CONFIG}) + # determine to which flags to add + if(NOT ${CONFIG} STREQUAL " ") + string(TOUPPER ${CONFIG} CONFIG) + set(CXX_FLAGS CMAKE_CXX_FLAGS_${CONFIG}) + set(C_FLAGS CMAKE_C_FLAGS_${CONFIG}) + else() + set(CXX_FLAGS CMAKE_CXX_FLAGS) + set(C_FLAGS CMAKE_C_FLAGS) + endif() + + # clear the old flags + if(${ARG_CLEAR_OLD}) + if("${ARG_CXX}" OR NOT "${ARG_C}") + set(${CXX_FLAGS} "") + endif() + if("${ARG_C}" OR NOT "${ARG_CXX}") + set(${C_FLAGS} "") + endif() + endif() + + # add all the passed flags + foreach(flag ${ARG_UNPARSED_ARGUMENTS}) + if("${ARG_CXX}" OR NOT "${ARG_C}") + set(${CXX_FLAGS} "${${CXX_FLAGS}} ${flag}") + endif() + if("${ARG_C}" OR NOT "${ARG_CXX}") + set(${C_FLAGS} "${${C_FLAGS}} ${flag}") + endif() + endforeach() + endforeach() + +endmacro() + +# ucm_set_flags +# Sets the CMAKE__FLAGS compiler flags or for a specific config +macro(ucm_set_flags) + ucm_add_flags(CLEAR_OLD ${ARGN}) +endmacro() + +# ucm_add_linker_flags +# Adds linker flags to CMAKE__LINKER_FLAGS or to a specific config +macro(ucm_add_linker_flags) + cmake_parse_arguments(ARG "CLEAR_OLD;EXE;MODULE;SHARED;STATIC" "" "CONFIG" ${ARGN}) + + if(NOT ARG_CONFIG) + set(ARG_CONFIG " ") + endif() + + foreach(CONFIG ${ARG_CONFIG}) + string(TOUPPER "${CONFIG}" CONFIG) + + if(NOT ${ARG_EXE} AND NOT ${ARG_MODULE} AND NOT ${ARG_SHARED} AND NOT ${ARG_STATIC}) + set(ARG_EXE 1) + set(ARG_MODULE 1) + set(ARG_SHARED 1) + set(ARG_STATIC 1) + endif() + + set(flags_configs "") + if(${ARG_EXE}) + if(NOT "${CONFIG}" STREQUAL " ") + list(APPEND flags_configs CMAKE_EXE_LINKER_FLAGS_${CONFIG}) + else() + list(APPEND flags_configs CMAKE_EXE_LINKER_FLAGS) + endif() + endif() + if(${ARG_MODULE}) + if(NOT "${CONFIG}" STREQUAL " ") + list(APPEND flags_configs CMAKE_MODULE_LINKER_FLAGS_${CONFIG}) + else() + list(APPEND flags_configs CMAKE_MODULE_LINKER_FLAGS) + endif() + endif() + if(${ARG_SHARED}) + if(NOT "${CONFIG}" STREQUAL " ") + list(APPEND flags_configs CMAKE_SHARED_LINKER_FLAGS_${CONFIG}) + else() + list(APPEND flags_configs CMAKE_SHARED_LINKER_FLAGS) + endif() + endif() + if(${ARG_STATIC}) + if(NOT "${CONFIG}" STREQUAL " ") + list(APPEND flags_configs CMAKE_STATIC_LINKER_FLAGS_${CONFIG}) + else() + list(APPEND flags_configs CMAKE_STATIC_LINKER_FLAGS) + endif() + endif() + + # clear the old flags + if(${ARG_CLEAR_OLD}) + foreach(flags ${flags_configs}) + set(${flags} "") + endforeach() + endif() + + # add all the passed flags + foreach(flag ${ARG_UNPARSED_ARGUMENTS}) + foreach(flags ${flags_configs}) + set(${flags} "${${flags}} ${flag}") + endforeach() + endforeach() + endforeach() +endmacro() + +# ucm_set_linker_flags +# Sets the CMAKE__LINKER_FLAGS linker flags or for a specific config +macro(ucm_set_linker_flags) + ucm_add_linker_flags(CLEAR_OLD ${ARGN}) +endmacro() + +# ucm_gather_flags +# Gathers all lists of flags for printing or manipulation +macro(ucm_gather_flags with_linker result) + set(${result} "") + # add the main flags without a config + list(APPEND ${result} CMAKE_C_FLAGS) + list(APPEND ${result} CMAKE_CXX_FLAGS) + if(${with_linker}) + list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS) + list(APPEND ${result} CMAKE_MODULE_LINKER_FLAGS) + list(APPEND ${result} CMAKE_SHARED_LINKER_FLAGS) + list(APPEND ${result} CMAKE_STATIC_LINKER_FLAGS) + endif() + + if("${CMAKE_CONFIGURATION_TYPES}" STREQUAL "" AND NOT "${CMAKE_BUILD_TYPE}" STREQUAL "") + # handle single config generators - like makefiles/ninja - when CMAKE_BUILD_TYPE is set + string(TOUPPER ${CMAKE_BUILD_TYPE} config) + list(APPEND ${result} CMAKE_C_FLAGS_${config}) + list(APPEND ${result} CMAKE_CXX_FLAGS_${config}) + if(${with_linker}) + list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_MODULE_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_SHARED_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_STATIC_LINKER_FLAGS_${config}) + endif() + else() + # handle multi config generators (like msvc, xcode) + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${config} config) + list(APPEND ${result} CMAKE_C_FLAGS_${config}) + list(APPEND ${result} CMAKE_CXX_FLAGS_${config}) + if(${with_linker}) + list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_MODULE_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_SHARED_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_STATIC_LINKER_FLAGS_${config}) + endif() + endforeach() + endif() +endmacro() + +# ucm_set_runtime +# Sets the runtime (static/dynamic) for msvc/gcc +macro(ucm_set_runtime) + cmake_parse_arguments(ARG "STATIC;DYNAMIC" "" "" ${ARGN}) + + if(ARG_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "unrecognized arguments: ${ARG_UNPARSED_ARGUMENTS}") + endif() + + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" STREQUAL "") + message(AUTHOR_WARNING "ucm_set_runtime() does not support clang yet!") + endif() + + ucm_gather_flags(0 flags_configs) + + # add/replace the flags + # note that if the user has messed with the flags directly this function might fail + # - for example if with MSVC and the user has removed the flags - here we just switch/replace them + if("${ARG_STATIC}") + foreach(flags ${flags_configs}) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(NOT ${flags} MATCHES "-static-libstdc\\+\\+") + set(${flags} "${${flags}} -static-libstdc++") + endif() + if(NOT ${flags} MATCHES "-static-libgcc") + set(${flags} "${${flags}} -static-libgcc") + endif() + elseif(MSVC) + if(${flags} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flags} "${${flags}}") + endif() + endif() + endforeach() + elseif("${ARG_DYNAMIC}") + foreach(flags ${flags_configs}) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(${flags} MATCHES "-static-libstdc\\+\\+") + string(REGEX REPLACE "-static-libstdc\\+\\+" "" ${flags} "${${flags}}") + endif() + if(${flags} MATCHES "-static-libgcc") + string(REGEX REPLACE "-static-libgcc" "" ${flags} "${${flags}}") + endif() + elseif(MSVC) + if(${flags} MATCHES "/MT") + string(REGEX REPLACE "/MT" "/MD" ${flags} "${${flags}}") + endif() + endif() + endforeach() + endif() +endmacro() + +# ucm_print_flags +# Prints all compiler flags for all configurations +macro(ucm_print_flags) + ucm_gather_flags(1 flags_configs) + message("") + foreach(flags ${flags_configs}) + message("${flags}: ${${flags}}") + endforeach() + message("") +endmacro() + +# ucm_count_sources +# Counts the number of source files +macro(ucm_count_sources) + cmake_parse_arguments(ARG "" "RESULT" "" ${ARGN}) + if(${ARG_RESULT} STREQUAL "") + message(FATAL_ERROR "Need to pass RESULT and a variable name to ucm_count_sources()") + endif() + + set(result 0) + foreach(SOURCE_FILE ${ARG_UNPARSED_ARGUMENTS}) + if("${SOURCE_FILE}" MATCHES \\.\(c|C|cc|cp|cpp|CPP|c\\+\\+|cxx|i|ii\)$) + math(EXPR result "${result} + 1") + endif() + endforeach() + set(${ARG_RESULT} ${result}) +endmacro() + +# ucm_include_file_in_sources +# Includes the file to the source with compiler flags +macro(ucm_include_file_in_sources) + cmake_parse_arguments(ARG "" "HEADER" "" ${ARGN}) + if(${ARG_HEADER} STREQUAL "") + message(FATAL_ERROR "Need to pass HEADER and a header file to ucm_include_file_in_sources()") + endif() + + foreach(src ${ARG_UNPARSED_ARGUMENTS}) + if(${src} MATCHES \\.\(c|C|cc|cp|cpp|CPP|c\\+\\+|cxx\)$) + # get old flags + get_source_file_property(old_compile_flags ${src} COMPILE_FLAGS) + if(old_compile_flags STREQUAL "NOTFOUND") + set(old_compile_flags "") + endif() + + # update flags + if(MSVC) + set_source_files_properties(${src} PROPERTIES COMPILE_FLAGS + "${old_compile_flags} /FI\"${CMAKE_CURRENT_SOURCE_DIR}/${ARG_HEADER}\"") + else() + set_source_files_properties(${src} PROPERTIES COMPILE_FLAGS + "${old_compile_flags} -include \"${CMAKE_CURRENT_SOURCE_DIR}/${ARG_HEADER}\"") + endif() + endif() + endforeach() +endmacro() + +# ucm_dir_list +# Returns a list of subdirectories for a given directory +macro(ucm_dir_list thedir result) + file(GLOB sub-dir "${thedir}/*") + set(list_of_dirs "") + foreach(dir ${sub-dir}) + if(IS_DIRECTORY ${dir}) + get_filename_component(DIRNAME ${dir} NAME) + LIST(APPEND list_of_dirs ${DIRNAME}) + endif() + endforeach() + set(${result} ${list_of_dirs}) +endmacro() + +# ucm_trim_front_words +# Trims X times the front word from a string separated with "/" and removes +# the front "/" characters after that (used for filters for visual studio) +macro(ucm_trim_front_words source out num_filter_trims) + set(result "${source}") + set(counter 0) + while(${counter} LESS ${num_filter_trims}) + MATH(EXPR counter "${counter} + 1") + # removes everything at the front up to a "/" character + string(REGEX REPLACE "^([^/]+)" "" result "${result}") + # removes all consecutive "/" characters from the front + string(REGEX REPLACE "^(/+)" "" result "${result}") + endwhile() + set(${out} ${result}) +endmacro() + +# ucm_remove_files +# Removes source files from a list of sources (path is the relative path for it to be found) +macro(ucm_remove_files) + cmake_parse_arguments(ARG "" "FROM" "" ${ARGN}) + + if("${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "Need to pass some relative files to ucm_remove_files()") + endif() + if(${ARG_FROM} STREQUAL "") + message(FATAL_ERROR "Need to pass FROM and a variable name to ucm_remove_files()") + endif() + + foreach(cur_file ${ARG_UNPARSED_ARGUMENTS}) + list(REMOVE_ITEM ${ARG_FROM} ${cur_file}) + endforeach() +endmacro() + +# ucm_remove_directories +# Removes all source files from the given directories from the sources list +macro(ucm_remove_directories) + cmake_parse_arguments(ARG "" "FROM" "MATCHES" ${ARGN}) + + if("${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "Need to pass some relative directories to ucm_remove_directories()") + endif() + if(${ARG_FROM} STREQUAL "") + message(FATAL_ERROR "Need to pass FROM and a variable name to ucm_remove_directories()") + endif() + + foreach(cur_dir ${ARG_UNPARSED_ARGUMENTS}) + foreach(cur_file ${${ARG_FROM}}) + string(REGEX MATCH ${cur_dir} res ${cur_file}) + if(NOT "${res}" STREQUAL "") + if("${ARG_MATCHES}" STREQUAL "") + list(REMOVE_ITEM ${ARG_FROM} ${cur_file}) + else() + foreach(curr_ptrn ${ARG_MATCHES}) + string(REGEX MATCH ${curr_ptrn} res ${cur_file}) + if(NOT "${res}" STREQUAL "") + list(REMOVE_ITEM ${ARG_FROM} ${cur_file}) + break() + endif() + endforeach() + endif() + endif() + endforeach() + endforeach() +endmacro() + +# ucm_add_files_impl +macro(ucm_add_files_impl result trim files) + foreach(cur_file ${files}) + SET(${result} ${${result}} ${cur_file}) + get_filename_component(FILEPATH ${cur_file} PATH) + ucm_trim_front_words("${FILEPATH}" FILEPATH "${trim}") + # replacing forward slashes with back slashes so filters can be generated (back slash used in parsing...) + STRING(REPLACE "/" "\\" FILTERS "${FILEPATH}") + SOURCE_GROUP("${FILTERS}" FILES ${cur_file}) + endforeach() +endmacro() + +# ucm_add_files +# Adds files to a list of sources +macro(ucm_add_files) + cmake_parse_arguments(ARG "" "TO;FILTER_POP" "" ${ARGN}) + + if("${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "Need to pass some relative files to ucm_add_files()") + endif() + if(${ARG_TO} STREQUAL "") + message(FATAL_ERROR "Need to pass TO and a variable name to ucm_add_files()") + endif() + + if("${ARG_FILTER_POP}" STREQUAL "") + set(ARG_FILTER_POP 0) + endif() + + ucm_add_files_impl(${ARG_TO} ${ARG_FILTER_POP} "${ARG_UNPARSED_ARGUMENTS}") +endmacro() + +# ucm_add_dir_impl +macro(ucm_add_dir_impl result rec trim dirs_in additional_ext) + set(dirs "${dirs_in}") + + # handle the "" and "." cases + if("${dirs}" STREQUAL "" OR "${dirs}" STREQUAL ".") + set(dirs "./") + endif() + + foreach(cur_dir ${dirs}) + # to circumvent some linux/cmake/path issues - barely made it work... + if(cur_dir STREQUAL "./") + set(cur_dir "") + else() + set(cur_dir "${cur_dir}/") + endif() + + # since unix is case sensitive - add these valid extensions too + # we don't use "UNIX" but instead "CMAKE_HOST_UNIX" because we might be cross + # compiling (for example emscripten) under windows and UNIX may be set to 1 + # Also OSX is case insensitive like windows... + set(additional_file_extensions "") + if(CMAKE_HOST_UNIX AND NOT APPLE) + set(additional_file_extensions + "${cur_dir}*.CPP" + "${cur_dir}*.C" + "${cur_dir}*.H" + "${cur_dir}*.HPP" + ) + endif() + + foreach(ext ${additional_ext}) + list(APPEND additional_file_extensions "${cur_dir}*.${ext}") + endforeach() + + # find all sources and set them as result + FILE(GLOB found_sources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" + # https://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Overall-Options.html#index-file-name-suffix-71 + # sources + "${cur_dir}*.cpp" + "${cur_dir}*.cxx" + "${cur_dir}*.c++" + "${cur_dir}*.cc" + "${cur_dir}*.cp" + "${cur_dir}*.c" + "${cur_dir}*.i" + "${cur_dir}*.ii" + # headers + "${cur_dir}*.h" + "${cur_dir}*.h++" + "${cur_dir}*.hpp" + "${cur_dir}*.hxx" + "${cur_dir}*.hh" + "${cur_dir}*.inl" + "${cur_dir}*.inc" + "${cur_dir}*.ipp" + "${cur_dir}*.ixx" + "${cur_dir}*.txx" + "${cur_dir}*.tpp" + "${cur_dir}*.tcc" + "${cur_dir}*.tpl" + ${additional_file_extensions}) + SET(${result} ${${result}} ${found_sources}) + + # set the proper filters + ucm_trim_front_words("${cur_dir}" cur_dir "${trim}") + # replacing forward slashes with back slashes so filters can be generated (back slash used in parsing...) + STRING(REPLACE "/" "\\" FILTERS "${cur_dir}") + SOURCE_GROUP("${FILTERS}" FILES ${found_sources}) + endforeach() + + if(${rec}) + foreach(cur_dir ${dirs}) + ucm_dir_list("${cur_dir}" subdirs) + foreach(subdir ${subdirs}) + ucm_add_dir_impl(${result} ${rec} ${trim} "${cur_dir}/${subdir}" "${additional_ext}") + endforeach() + endforeach() + endif() +endmacro() + +# ucm_add_dirs +# Adds all files from directories traversing them recursively to a list of sources +# and generates filters according to their location (accepts relative paths only). +# Also this macro trims X times the front word from the filter string for visual studio filters. +macro(ucm_add_dirs) + cmake_parse_arguments(ARG "RECURSIVE" "TO;FILTER_POP" "ADDITIONAL_EXT" ${ARGN}) + + if(${ARG_TO} STREQUAL "") + message(FATAL_ERROR "Need to pass TO and a variable name to ucm_add_dirs()") + endif() + + if("${ARG_FILTER_POP}" STREQUAL "") + set(ARG_FILTER_POP 0) + endif() + + ucm_add_dir_impl(${ARG_TO} ${ARG_RECURSIVE} ${ARG_FILTER_POP} "${ARG_UNPARSED_ARGUMENTS}" "${ARG_ADDITIONAL_EXT}") +endmacro() + +# ucm_add_target +# Adds a target eligible for cotiring - unity build and/or precompiled header +macro(ucm_add_target) + cmake_parse_arguments(ARG "UNITY" "NAME;TYPE;PCH_FILE;CPP_PER_UNITY" "UNITY_EXCLUDED;SOURCES" ${ARGN}) + + if(NOT "${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "Unrecognized options passed to ucm_add_target()") + endif() + if("${ARG_NAME}" STREQUAL "") + message(FATAL_ERROR "Need to pass NAME and a name for the target to ucm_add_target()") + endif() + set(valid_types EXECUTABLE STATIC SHARED MODULE) + list(FIND valid_types "${ARG_TYPE}" is_type_valid) + if(${is_type_valid} STREQUAL "-1") + message(FATAL_ERROR "Need to pass TYPE and the type for the target [EXECUTABLE/STATIC/SHARED/MODULE] to ucm_add_target()") + endif() + if("${ARG_SOURCES}" STREQUAL "") + message(FATAL_ERROR "Need to pass SOURCES and a list of source files to ucm_add_target()") + endif() + + # init with the global unity flag + set(do_unity ${UCM_UNITY_BUILD}) + + # check the UNITY argument + if(NOT ARG_UNITY) + set(do_unity FALSE) + endif() + + # if target is excluded through the exclusion list + list(FIND UCM_UNITY_BUILD_EXCLUDE_TARGETS ${ARG_NAME} is_target_excluded) + if(NOT ${is_target_excluded} STREQUAL "-1") + set(do_unity FALSE) + endif() + + # unity build only for targets with > 1 source file (otherwise there will be an additional unnecessary target) + if(do_unity) # optimization + ucm_count_sources(${ARG_SOURCES} RESULT num_sources) + if(${num_sources} LESS 2) + set(do_unity FALSE) + endif() + endif() + + set(wanted_cotire ${do_unity}) + + # if cotire cannot be used + if(do_unity AND NOT ucm_with_cotire) + set(do_unity FALSE) + endif() + + # inform the developer that the current target might benefit from a unity build + if(NOT ARG_UNITY AND ${UCM_UNITY_BUILD}) + ucm_count_sources(${ARG_SOURCES} RESULT num_sources) + if(${num_sources} GREATER 1) + message(AUTHOR_WARNING "Target '${ARG_NAME}' may benefit from a unity build.\nIt has ${num_sources} sources - enable with UNITY flag") + endif() + endif() + + # prepare for the unity build + set(orig_target ${ARG_NAME}) + if(do_unity) + # the original target will be added with a different name than the requested + set(orig_target ${ARG_NAME}_ORIGINAL) + + # exclude requested files from unity build of the current target + foreach(excluded_file "${ARG_UNITY_EXCLUDED}") + set_source_files_properties(${excluded_file} PROPERTIES COTIRE_EXCLUDED TRUE) + endforeach() + endif() + + # add the original target + if(${ARG_TYPE} STREQUAL "EXECUTABLE") + add_executable(${orig_target} ${ARG_SOURCES}) + else() + add_library(${orig_target} ${ARG_TYPE} ${ARG_SOURCES}) + endif() + + if(do_unity) + # set the number of unity cpp files to be used for the unity target + if(NOT "${ARG_CPP_PER_UNITY}" STREQUAL "") + set_property(TARGET ${orig_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${ARG_CPP_PER_UNITY}") + else() + set_property(TARGET ${orig_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "100") + endif() + + if(NOT "${ARG_PCH_FILE}" STREQUAL "") + set_target_properties(${orig_target} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${ARG_PCH_FILE}") + else() + set_target_properties(${orig_target} PROPERTIES COTIRE_ENABLE_PRECOMPILED_HEADER FALSE) + endif() + # add a unity target for the original one with the name intended for the original + set_target_properties(${orig_target} PROPERTIES COTIRE_UNITY_TARGET_NAME ${ARG_NAME}) + + # this is the library call that does the magic + cotire(${orig_target}) + set_target_properties(clean_cotire PROPERTIES FOLDER "CMakePredefinedTargets") + + # disable the original target and enable the unity one + get_target_property(unity_target_name ${orig_target} COTIRE_UNITY_TARGET_NAME) + set_target_properties(${orig_target} PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1) + set_target_properties(${unity_target_name} PROPERTIES EXCLUDE_FROM_ALL 0 EXCLUDE_FROM_DEFAULT_BUILD 0) + + # also set the name of the target output as the original one + set_target_properties(${unity_target_name} PROPERTIES OUTPUT_NAME ${ARG_NAME}) + if(UCM_NO_COTIRE_FOLDER) + # reset the folder property so all unity targets dont end up in a single folder in the solution explorer of VS + set_target_properties(${unity_target_name} PROPERTIES FOLDER "") + endif() + set_target_properties(all_unity PROPERTIES FOLDER "CMakePredefinedTargets") + elseif(NOT "${ARG_PCH_FILE}" STREQUAL "") + set(wanted_cotire TRUE) + if(ucm_with_cotire) + set_target_properties(${orig_target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) + set_target_properties(${orig_target} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${ARG_PCH_FILE}") + cotire(${orig_target}) + set_target_properties(clean_cotire PROPERTIES FOLDER "CMakePredefinedTargets") + endif() + endif() + + # print a message if the target was requested to be cotired but it couldn't + if(wanted_cotire AND NOT ucm_with_cotire) + if(NOT COMMAND cotire) + message(AUTHOR_WARNING "Target \"${ARG_NAME}\" not cotired because cotire isn't loaded") + else() + message(AUTHOR_WARNING "Target \"${ARG_NAME}\" not cotired because cotire is older than the required version") + endif() + endif() +endmacro() \ No newline at end of file diff --git a/contrib/cmake/src/CMakeLists.txt b/contrib/cmake/src/CMakeLists.txt new file mode 100644 index 00000000..d13de033 --- /dev/null +++ b/contrib/cmake/src/CMakeLists.txt @@ -0,0 +1,316 @@ +# ECC Build System +# +# This CMakeLists.txt is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Fixes +set(CONTRIB_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +string(REGEX REPLACE "/contrib/cmake" "" CMAKE_CURRENT_SOURCE_DIR + ${CMAKE_CURRENT_SOURCE_DIR}) + +# Compile the `build.h` Header +string(TIMESTAMP BUILD_DATETIME UTC) +configure_file(build.h.in build.h) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +# Setup Sources +set(DIR_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/txdb.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/key.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/addrman.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/amount.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/arith_uint256.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/base58.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/chain/blockindex.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bloom.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/chain/chain.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/chain/chainman.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/networks/netman.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/chain/checkpoints.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/clientversion.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/coins.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/compressor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/core_read.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/core_write.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/dbwrapper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/hash.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/keystore.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/merkleblock.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/messages.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/miner.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/net.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/netbase.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/noui.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/pow.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processblock.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processheader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/protocol.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/pubkey.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/random.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/scheduler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sync.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/timedata.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/torcontrol.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/txmempool.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/uint256.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/util/util.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/fs.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/args.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/util/utilmoneystr.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/util/utilstrencodings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/util/utiltime.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/validationinterface.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/versionbits.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/wallet/crypter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/wallet/db.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/wallet/wallet.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/wallet/wallet_ismine.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/wallet/walletdb.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/support/cleanse.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/support/pagelocker.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/script/bitcoinconsensus.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/script/interpreter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/script/script.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/script/script_error.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/script/sigcache.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/script/sign.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/script/standard.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/chain/block.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tx/tx.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/policy/fees.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/policy/policy.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/policy/rbf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/hmac_sha256.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/hmac_sha512.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/ripemd160.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/sha1.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/sha256.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/sha512.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/chacha20.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/consensus/merkle.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/compat/glibc_compat.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/compat/glibc_sanity.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/compat/glibcxx_sanity.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/compat/strnlen.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/init.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/eccoind.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/scrypt.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/kernel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/httprpc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/httpserver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rest.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcblockchain.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcclient.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcdump.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcmining.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcmisc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcnet.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcprotocol.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcrawtransaction.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcserver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcwallet.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/univalue/univalue.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/univalue/univalue_read.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/univalue/univalue_write.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/pbkdf2.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/script/stakescript.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/signals.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processtx.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/verifydb.cpp ) + +set(DIR_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/txdb.h + ${CMAKE_CURRENT_SOURCE_DIR}/key.h + ${CMAKE_CURRENT_SOURCE_DIR}/addrman.h + ${CMAKE_CURRENT_SOURCE_DIR}/amount.h + ${CMAKE_CURRENT_SOURCE_DIR}/arith_uint256.h + ${CMAKE_CURRENT_SOURCE_DIR}/base58.h + ${CMAKE_CURRENT_SOURCE_DIR}/chain/blockindex.h + ${CMAKE_CURRENT_SOURCE_DIR}/bloom.h + ${CMAKE_CURRENT_SOURCE_DIR}/chain/chain.h + ${CMAKE_CURRENT_SOURCE_DIR}/chain/chainman.h + ${CMAKE_CURRENT_SOURCE_DIR}/networks/netman.h + ${CMAKE_CURRENT_SOURCE_DIR}/chain/checkpoints.h + ${CMAKE_CURRENT_SOURCE_DIR}/clientversion.h + ${CMAKE_CURRENT_SOURCE_DIR}/coins.h + ${CMAKE_CURRENT_SOURCE_DIR}/compressor.h + ${CMAKE_CURRENT_SOURCE_DIR}/dbwrapper.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/hash.h + ${CMAKE_CURRENT_SOURCE_DIR}/keystore.h + ${CMAKE_CURRENT_SOURCE_DIR}/main.h + ${CMAKE_CURRENT_SOURCE_DIR}/merkleblock.h + ${CMAKE_CURRENT_SOURCE_DIR}/messages.h + ${CMAKE_CURRENT_SOURCE_DIR}/miner.h + ${CMAKE_CURRENT_SOURCE_DIR}/net.h + ${CMAKE_CURRENT_SOURCE_DIR}/netbase.h + ${CMAKE_CURRENT_SOURCE_DIR}/noui.h + ${CMAKE_CURRENT_SOURCE_DIR}/pow.h + ${CMAKE_CURRENT_SOURCE_DIR}/processblock.h + ${CMAKE_CURRENT_SOURCE_DIR}/processheader.h + ${CMAKE_CURRENT_SOURCE_DIR}/protocol.h + ${CMAKE_CURRENT_SOURCE_DIR}/pubkey.h + ${CMAKE_CURRENT_SOURCE_DIR}/random.h + ${CMAKE_CURRENT_SOURCE_DIR}/scheduler.h + ${CMAKE_CURRENT_SOURCE_DIR}/sync.h + ${CMAKE_CURRENT_SOURCE_DIR}/timedata.h + ${CMAKE_CURRENT_SOURCE_DIR}/torcontrol.h + ${CMAKE_CURRENT_SOURCE_DIR}/txmempool.h + ${CMAKE_CURRENT_SOURCE_DIR}/uint256.h + ${CMAKE_CURRENT_SOURCE_DIR}/util/util.h + ${CMAKE_CURRENT_SOURCE_DIR}/fs.h + ${CMAKE_CURRENT_SOURCE_DIR}/args.h + ${CMAKE_CURRENT_SOURCE_DIR}/util/utilmoneystr.h + ${CMAKE_CURRENT_SOURCE_DIR}/util/utilstrencodings.h + ${CMAKE_CURRENT_SOURCE_DIR}/util/utiltime.h + ${CMAKE_CURRENT_SOURCE_DIR}/validationinterface.h + ${CMAKE_CURRENT_SOURCE_DIR}/versionbits.h + ${CMAKE_CURRENT_SOURCE_DIR}/wallet/crypter.h + ${CMAKE_CURRENT_SOURCE_DIR}/wallet/db.h + ${CMAKE_CURRENT_SOURCE_DIR}/wallet/wallet.h + ${CMAKE_CURRENT_SOURCE_DIR}/wallet/wallet_ismine.h + ${CMAKE_CURRENT_SOURCE_DIR}/wallet/walletdb.h + ${CMAKE_CURRENT_SOURCE_DIR}/support/cleanse.h + ${CMAKE_CURRENT_SOURCE_DIR}/support/pagelocker.h + ${CMAKE_CURRENT_SOURCE_DIR}/script/bitcoinconsensus.h + ${CMAKE_CURRENT_SOURCE_DIR}/script/interpreter.h + ${CMAKE_CURRENT_SOURCE_DIR}/script/script.h + ${CMAKE_CURRENT_SOURCE_DIR}/script/script_error.h + ${CMAKE_CURRENT_SOURCE_DIR}/script/sigcache.h + ${CMAKE_CURRENT_SOURCE_DIR}/script/sign.h + ${CMAKE_CURRENT_SOURCE_DIR}/script/standard.h + ${CMAKE_CURRENT_SOURCE_DIR}/chain/block.h + ${CMAKE_CURRENT_SOURCE_DIR}/tx/tx.h + ${CMAKE_CURRENT_SOURCE_DIR}/policy/fees.h + ${CMAKE_CURRENT_SOURCE_DIR}/policy/policy.h + ${CMAKE_CURRENT_SOURCE_DIR}/policy/rbf.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/hmac_sha256.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/hmac_sha512.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/ripemd160.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/sha1.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/sha256.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/sha512.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/chacha20.h + ${CMAKE_CURRENT_SOURCE_DIR}/consensus/merkle.h + ${CMAKE_CURRENT_SOURCE_DIR}/init.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto/scrypt.h + ${CMAKE_CURRENT_SOURCE_DIR}/kernel.h + ${CMAKE_CURRENT_SOURCE_DIR}/httprpc.h + ${CMAKE_CURRENT_SOURCE_DIR}/httpserver.h + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcclient.h + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcprotocol.h + ${CMAKE_CURRENT_SOURCE_DIR}/rpc/rpcserver.h + ${CMAKE_CURRENT_SOURCE_DIR}/univalue/univalue.h + ${CMAKE_CURRENT_SOURCE_DIR}/pbkdf2.h + ${CMAKE_CURRENT_SOURCE_DIR}/script/stakescript.h + ${CMAKE_CURRENT_SOURCE_DIR}/signals.h + ${CMAKE_CURRENT_SOURCE_DIR}/processtx.h + ${CMAKE_CURRENT_SOURCE_DIR}/verifydb.h ) + +# +# Boost Dependencies +# +set(Boost_USE_STATIC_LIBS OFF) +set(Boost_USE_MULTITHREADED ON) +set(Boost_USE_STATIC_RUNTIME OFF) +find_package( Boost REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options ) +include_directories( ${Boost_INCLUDE_DIR} ) +# ucm_add_linker_flags(SHARED ${Boost_LIBRARY_DIRS}) + +# +# OpenSSL Dependencies +# +find_package(OpenSSL REQUIRED) +include_directories(${OPENSSL_INCLUDE_DIR}) +# ucm_add_linker_flags(SHARED ${OPENSSL_LIBRARIES}) + +# +# LibEvent Dependencies +# +find_package(LibEvent REQUIRED) +include_directories(${LIBEVENT_INCLUDE_DIR}) +# ucm_add_linker_flags(SHARED ${LIBEVENT_LIB}) + +# +# BerkeleyDB +# +set(DB_VERSION 47) +find_package(BerkeleyDB REQUIRED) +include_directories(${BERKELEY_DB_INCLUDE_DIR}) +# ucm_add_linker_flags(SHARED ${BERKELEY_DB_LIBRARIES}) + +# +# LevelDB +# +add_subdirectory(leveldb) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/leveldb/include + ${CMAKE_CURRENT_SOURCE_DIR}/leveldb/helpers + ${CMAKE_CURRENT_SOURCE_DIR}/leveldb/helpers/memenv) + + + +# +# univalue +# +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/univalue) + +# +# ECCoin +# +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +add_library(eccoin ${DIR_HEADERS} ${DIR_SOURCES}) + + +# +# secp256k1 - uses the original autotools +# +include(ExternalProject) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/secp256k1/include) +ExternalProject_Add(SECP_EXTERNAL + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/secp256k1 + CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/secp256k1/configure + BUILD_COMMAND ${MAKE} + INSTALL_COMMAND "") + +ExternalProject_Get_Property(SECP_EXTERNAL INSTALL_DIR) +set(SECKP_DIR ${INSTALL_DIR}) +add_dependencies(eccoin SECP_EXTERNAL) + +target_link_libraries(eccoin + ${SECKP_DIR}/src/SECP_EXTERNAL-build + ${Boost_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${LIBEVENT_LIB} + ${BERKELEY_DB_LIBRARIES} + event_pthreads + secp256k1 + leveldb + +) + +# add_library(SECP_LIB STATIC IMPORTED GLOBAL) +# set_property(TARGET SECP_LIB PROPERTY IMPORTED_LOCATION ${SECKP_DIR}/src/secp256k1-build/libsecp256k1.la) +# add_dependencies(SECP_LIB secp256k1) + + +add_executable(eccoind ${DIR_HEADERS} ${DIR_SOURCES}) +target_link_libraries(eccoind eccoin) + +# include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +# add_executable(eccoind ${DIR_HEADERS} ${DIR_SOURCES}) +# target_link_libraries(eccoin +# leveldb +# -L${SECKP_DIR}/src/secp256k1-build +# ${Boost_LIBRARY_DIRS} +# ${OPENSSL_LIBRARIES} +# ${LIBEVENT_LIB} +# ${BERKELEY_DB_LIBRARIES} +# ) + +# ucm_print_flags() \ No newline at end of file diff --git a/contrib/cmake/src/build.h.in b/contrib/cmake/src/build.h.in new file mode 100644 index 00000000..98d07b59 --- /dev/null +++ b/contrib/cmake/src/build.h.in @@ -0,0 +1,2 @@ +#define BUILD_SUFFIX "@GIT_SHA1@" +#define BUILD_DATE "@BUILD_DATETIME@" \ No newline at end of file diff --git a/contrib/cmake/src/leveldb/CMakeLists.txt b/contrib/cmake/src/leveldb/CMakeLists.txt new file mode 100644 index 00000000..86b81029 --- /dev/null +++ b/contrib/cmake/src/leveldb/CMakeLists.txt @@ -0,0 +1,228 @@ +# Copyright 2017 The LEVELDB Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. See the AUTHORS file for names of contributors. + +# Fixes +set(CONTRIB_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +string(REGEX REPLACE "/contrib/cmake" "" CMAKE_CURRENT_SOURCE_DIR + ${CMAKE_CURRENT_SOURCE_DIR}) + +cmake_minimum_required(VERSION 3.1) +project(Leveldb VERSION 0.1.0 LANGUAGES C CXX) + +# This project can take advantage of C++11. +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED OFF) +# TODO(pwnall): See if setting this to ON gives us the *_unlocked functions. +set(CMAKE_CXX_EXTENSIONS OFF) + +include(TestBigEndian) +test_big_endian(LEVELDB_IS_BIG_ENDIAN) + +include(CheckIncludeFile) +check_include_file("unistd.h" HAVE_UNISTD_H) + +include(CheckIncludeFileCXX) +check_include_file_cxx("atomic" LEVELDB_ATOMIC_PRESENT) + +include(CheckLibraryExists) +check_library_exists(crc32c crc32c_value "" HAVE_CRC32C) +check_library_exists(snappy snappy_compress "" HAVE_SNAPPY) + +include(CheckSymbolExists) +check_symbol_exists(fdatasync "unistd.h" HAVE_FDATASYNC) + + +# Check Operating System +# CMake does not distinguish Linux from other Unices. +STRING (REGEX MATCH "Linux" PROJECT_OS_LINUX ${CMAKE_SYSTEM_NAME}) +# Nor *BSD +STRING (REGEX MATCH "BSD" PROJECT_OS_BSD ${CMAKE_SYSTEM_NAME}) +# Or Solaris. I'm seeing a trend, here +STRING (REGEX MATCH "SunOS" PROJECT_OS_SOLARIS ${CMAKE_SYSTEM_NAME}) + +# Windows is easy (for once) +IF (WIN32) + SET (PROJECT_OS_WIN TRUE BOOL INTERNAL) +ENDIF (WIN32) + +# Check if it's an Apple OS +IF (APPLE) + # Check if it's OS X or another MacOS (that's got to be pretty unlikely) + STRING (REGEX MATCH "Darwin" PROJECT_OS_OSX ${CMAKE_SYSTEM_NAME}) + IF (NOT PROJECT_OS_OSX) + SET (PROJECT_OS_MACOS TRUE BOOL INTERNAL) + ENDIF (NOT PROJECT_OS_OSX) +ENDIF (APPLE) +add_definitions(-DLEVELDB_ATOMIC_PRESENT) +IF (PROJECT_OS_LINUX) + SET(OS_LINUX 1) + add_definitions(-DOS_LINUX) + add_definitions(-DLEVELDB_PLATFORM_POSIX) +ELSEIF (PROJECT_OS_BSD) + SET(OS_FREEBSD 1) + add_definitions(-DOS_FREEBSD) + add_definitions(-DLEVELDB_PLATFORM_POSIX) +ELSEIF (PROJECT_OS_WIN) + SET(OS_WINDOWS 1) + add_definitions(-DOS_WINDOWS) +ELSEIF (PROJECT_OS_OSX) + SET(OS_MACOSX 1) + add_definitions(-DOS_MACOSX) + add_definitions(-DLEVELDB_PLATFORM_POSIX) +ELSEIF (PROJECT_OS_MACOS) + SET(OS_MACOSX 1) + add_definitions(-DOS_MACOSX) + add_definitions(-DLEVELDB_PLATFORM_POSIX) +ELSEIF (PROJECT_OS_SOLARIS) + SET(OS_SOLARIS 1) + add_definitions(-DOS_SOLARIS) +ELSE (PROJECT_OS_LINUX) + SET(OS_LINUX 1) + add_definitions(-DOS_LINUX) + add_definitions(-DLEVELDB_PLATFORM_POSIX) +ENDIF (PROJECT_OS_LINUX) + +configure_file( + "${CONTRIB_CURRENT_SOURCE_DIR}/include/port/port_config.h.in" + "${PROJECT_BINARY_DIR}/include/port/port_config.h" +) + +include_directories( + "${PROJECT_BINARY_DIR}/include" + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}/include" +) + +# POSIX code is specified separately so we can leave it out in the future. +add_library(leveldb_port_posix OBJECT "") +target_sources(leveldb_port_posix + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/port/port_posix.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/port/port_posix_sse.cc" + + PUBLIC + # The headers below are dependencies for leveldb, but aren't needed by users + # that link to the installed version of leveldb and rely on its public API. + $ + $ + $ + $ +) + +add_library(leveldb "" + # TODO(pwnall): Move the TARGET_OBJECTS generator expressions to the PRIVATE + # section of target_sources when cmake_minimum_required becomes 3.9 or above. + $ +) +target_sources(leveldb + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/db/builder.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/builder.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/c.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/db_impl.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/db_impl.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/db_iter.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/db_iter.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/dbformat.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/dbformat.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/dumpfile.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/filename.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/filename.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/log_format.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/log_reader.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/log_reader.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/log_writer.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/log_writer.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/memtable.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/memtable.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/repair.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/skiplist.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/snapshot.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/table_cache.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/table_cache.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/version_edit.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/version_edit.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/version_set.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/db/version_set.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/write_batch_internal.h" + "${CMAKE_CURRENT_SOURCE_DIR}/db/write_batch.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/port/port.h" + "${CMAKE_CURRENT_SOURCE_DIR}/port/thread_annotations.h" + "${CMAKE_CURRENT_SOURCE_DIR}/table/block_builder.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/table/block_builder.h" + "${CMAKE_CURRENT_SOURCE_DIR}/table/block.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/table/block.h" + "${CMAKE_CURRENT_SOURCE_DIR}/table/filter_block.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/table/filter_block.h" + "${CMAKE_CURRENT_SOURCE_DIR}/table/format.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/table/format.h" + "${CMAKE_CURRENT_SOURCE_DIR}/table/iterator_wrapper.h" + "${CMAKE_CURRENT_SOURCE_DIR}/table/iterator.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/table/merger.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/table/merger.h" + "${CMAKE_CURRENT_SOURCE_DIR}/table/table_builder.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/table/table.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/table/two_level_iterator.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/table/two_level_iterator.h" + "${CMAKE_CURRENT_SOURCE_DIR}/util/arena.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/util/arena.h" + "${CMAKE_CURRENT_SOURCE_DIR}/util/bloom.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/util/cache.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/util/coding.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/util/coding.h" + "${CMAKE_CURRENT_SOURCE_DIR}/util/comparator.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/util/crc32c.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/util/crc32c.h" + "${CMAKE_CURRENT_SOURCE_DIR}/util/env_posix.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/util/env.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/util/filter_policy.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/util/hash.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/util/hash.h" + "${CMAKE_CURRENT_SOURCE_DIR}/util/logging.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/util/logging.h" + "${CMAKE_CURRENT_SOURCE_DIR}/util/mutexlock.h" + "${CMAKE_CURRENT_SOURCE_DIR}/util/options.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/util/posix_logger.h" + "${CMAKE_CURRENT_SOURCE_DIR}/util/random.h" + "${CMAKE_CURRENT_SOURCE_DIR}/util/status.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/helpers/memenv/memenv.cc" + + # Only CMake 3.3+ supports PUBLIC sources in targets exported by "install". + $<$:PUBLIC> + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/c.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/cache.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/comparator.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/db.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/dumpfile.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/env.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/filter_policy.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/iterator.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/options.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/slice.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/status.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/table_builder.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/table.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/leveldb/write_batch.h" +) +target_include_directories(leveldb + PUBLIC + $ + $ +) +target_compile_definitions(leveldb + PRIVATE + LEVELDB_PLATFORM_POSIX +) + +# TODO(pwnall): This is only needed for port_posix. +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) +target_link_libraries(leveldb Threads::Threads) + +if (HAVE_CRC32C) + target_link_libraries(leveldb crc32c) +endif (HAVE_CRC32C) +if (HAVE_SNAPPY) + target_link_libraries(leveldb snappy) +endif (HAVE_SNAPPY) diff --git a/contrib/cmake/src/leveldb/include/port/port_config.h.in b/contrib/cmake/src/leveldb/include/port/port_config.h.in new file mode 100644 index 00000000..bcb18234 --- /dev/null +++ b/contrib/cmake/src/leveldb/include/port/port_config.h.in @@ -0,0 +1,56 @@ +// Copyright 2017 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_PORT_PORT_CONFIG_H_ +#define STORAGE_LEVELDB_PORT_PORT_CONFIG_H_ + +// Define to 1 if you have a definition for fdatasync() in . +#if !defined(HAVE_FUNC_FDATASYNC) +#cmakedefine01 HAVE_FUNC_FDATASYNC +#endif // !defined(HAVE_FUNC_FDATASYNC) + +// Define to 1 if you have Google CRC32C. +#if !defined(HAVE_CRC32C) +#cmakedefine01 HAVE_CRC32C +#endif // !defined(HAVE_CRC32C) + +// Define to 1 if you have Google Snappy. +#if !defined(HAVE_SNAPPY) +#cmakedefine01 HAVE_SNAPPY +#endif // !defined(HAVE_SNAPPY) + +// Define to 1 if you have the header file. +#if !defined(HAVE_UNISTD_H) +#cmakedefine01 HAVE_UNISTD_H +#endif // !defined(HAVE_UNISTD_H) + +// Define to 1 if your processor stores words with the most significant byte +// first (like Motorola and SPARC, unlike Intel and VAX). +#if !defined(LEVELDB_IS_BIG_ENDIAN) +#cmakedefine01 LEVELDB_IS_BIG_ENDIAN +#endif // !defined(LEVELDB_IS_BIG_ENDIAN) + + +// Define Platform +#if !defined(OS_LINUX) +#cmakedefine01 OS_LINUX +#endif // !defined(OS_LINUX) + +#if !defined(OS_FREEBSD) +#cmakedefine01 OS_FREEBSD +#endif // !defined(OS_FREEBSD) + +#if !defined(OS_WINDOWS) +#cmakedefine01 OS_WINDOWS +#endif // !defined(OS_WINDOWS) + +#if !defined(OS_MACOSX) +#cmakedefine01 OS_MACOSX +#endif // !defined(OS_MACOSX) + +#if !defined(OS_SOLARIS) +#cmakedefine01 OS_SOLARIS +#endif // !defined(OS_SOLARIS) + +#endif // STORAGE_LEVELDB_PORT_PORT_CONFIG_H_ \ No newline at end of file diff --git a/depends/.gitignore b/depends/.gitignore new file mode 100644 index 00000000..3cb4b9ac --- /dev/null +++ b/depends/.gitignore @@ -0,0 +1,10 @@ +SDKs/ +work/ +built/ +sources/ +config.site +x86_64* +i686* +mips* +arm* +aarch64* diff --git a/depends/Makefile b/depends/Makefile new file mode 100644 index 00000000..52d27280 --- /dev/null +++ b/depends/Makefile @@ -0,0 +1,167 @@ +.NOTPARALLEL : + +SOURCES_PATH ?= $(BASEDIR)/sources +BASE_CACHE ?= $(BASEDIR)/built +SDK_PATH ?= $(BASEDIR)/SDKs +NO_QT ?= +NO_WALLET ?= +NO_UPNP ?= +FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources + +BUILD = $(shell ./config.guess) +HOST ?= $(BUILD) +PATCHES_PATH = $(BASEDIR)/patches +BASEDIR = $(CURDIR) +HASH_LENGTH:=11 +DOWNLOAD_CONNECT_TIMEOUT:=10 +DOWNLOAD_RETRIES:=3 + +host:=$(BUILD) +ifneq ($(HOST),) +host:=$(HOST) +host_toolchain:=$(HOST)- +endif + +ifneq ($(DEBUG),) +release_type=debug +else +release_type=release +endif + +base_build_dir=$(BASEDIR)/work/build +base_staging_dir=$(BASEDIR)/work/staging +base_download_dir=$(BASEDIR)/work/download +canonical_host:=$(shell ./config.sub $(HOST)) +build:=$(shell ./config.sub $(BUILD)) + +build_arch =$(firstword $(subst -, ,$(build))) +build_vendor=$(word 2,$(subst -, ,$(build))) +full_build_os:=$(subst $(build_arch)-$(build_vendor)-,,$(build)) +build_os:=$(findstring linux,$(full_build_os)) +build_os+=$(findstring darwin,$(full_build_os)) +build_os:=$(strip $(build_os)) +ifeq ($(build_os),) +build_os=$(full_build_os) +endif + +host_arch=$(firstword $(subst -, ,$(canonical_host))) +host_vendor=$(word 2,$(subst -, ,$(canonical_host))) +full_host_os:=$(subst $(host_arch)-$(host_vendor)-,,$(canonical_host)) +host_os:=$(findstring linux,$(full_host_os)) +host_os+=$(findstring darwin,$(full_host_os)) +host_os+=$(findstring mingw32,$(full_host_os)) +host_os:=$(strip $(host_os)) +ifeq ($(host_os),) +host_os=$(full_host_os) +endif + +$(host_arch)_$(host_os)_prefix=$(BASEDIR)/$(host) +$(host_arch)_$(host_os)_host=$(host) +host_prefix=$($(host_arch)_$(host_os)_prefix) +build_prefix=$(host_prefix)/native +build_host=$(build) + +AT_$(V):= +AT_:=@ +AT:=$(AT_$(V)) + +all: install + +include hosts/$(host_os).mk +include hosts/default.mk +include builders/$(build_os).mk +include builders/default.mk +include packages/packages.mk + +qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch)_$(host_os)_packages) + +wallet_packages_$(NO_WALLET) = $(wallet_packages) +upnp_packages_$(NO_UPNP) = $(upnp_packages) + +packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) +native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages) + +ifneq ($(qt_packages_),) +native_packages += $(qt_native_packages) +endif + +all_packages = $(packages) $(native_packages) + +meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk + +$(host_arch)_$(host_os)_native_toolchain?=$($(host_os)_native_toolchain) + +include funcs.mk + +toolchain_path=$($($(host_arch)_$(host_os)_native_toolchain)_prefixbin) +final_build_id_long+=$(shell $(build_SHA256SUM) config.site.in) +final_build_id+=$(shell echo -n $(final_build_id_long) | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH)) +$(host_prefix)/.stamp_$(final_build_id): $(native_packages) $(packages) + $(AT)rm -rf $(@D) + $(AT)mkdir -p $(@D) + $(AT)echo copying packages: $^ + $(AT)echo to: $(@D) + $(AT)cd $(@D); $(foreach package,$^, tar xf $($(package)_cached); ) + $(AT)touch $@ + +$(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_build_id) + $(AT)@mkdir -p $(@D) + $(AT)sed -e 's|@HOST@|$(host)|' \ + -e 's|@CC@|$(toolchain_path)$(host_CC)|' \ + -e 's|@CXX@|$(toolchain_path)$(host_CXX)|' \ + -e 's|@AR@|$(toolchain_path)$(host_AR)|' \ + -e 's|@RANLIB@|$(toolchain_path)$(host_RANLIB)|' \ + -e 's|@NM@|$(toolchain_path)$(host_NM)|' \ + -e 's|@STRIP@|$(toolchain_path)$(host_STRIP)|' \ + -e 's|@build_os@|$(build_os)|' \ + -e 's|@host_os@|$(host_os)|' \ + -e 's|@CFLAGS@|$(strip $(host_CFLAGS) $(host_$(release_type)_CFLAGS))|' \ + -e 's|@CXXFLAGS@|$(strip $(host_CXXFLAGS) $(host_$(release_type)_CXXFLAGS))|' \ + -e 's|@CPPFLAGS@|$(strip $(host_CPPFLAGS) $(host_$(release_type)_CPPFLAGS))|' \ + -e 's|@LDFLAGS@|$(strip $(host_LDFLAGS) $(host_$(release_type)_LDFLAGS))|' \ + -e 's|@allow_host_packages@|$(ALLOW_HOST_PACKAGES)|' \ + -e 's|@no_qt@|$(NO_QT)|' \ + -e 's|@no_wallet@|$(NO_WALLET)|' \ + -e 's|@no_upnp@|$(NO_UPNP)|' \ + -e 's|@debug@|$(DEBUG)|' \ + $< > $@ + $(AT)touch $@ + + +define check_or_remove_cached + mkdir -p $(BASE_CACHE)/$(host)/$(package) && cd $(BASE_CACHE)/$(host)/$(package); \ + $(build_SHA256SUM) -c $($(package)_cached_checksum) >/dev/null 2>/dev/null || \ + ( rm -f $($(package)_cached_checksum); \ + if test -f "$($(package)_cached)"; then echo "Checksum mismatch for $(package). Forcing rebuild.."; rm -f $($(package)_cached_checksum) $($(package)_cached); fi ) +endef + +define check_or_remove_sources + mkdir -p $($(package)_source_dir); cd $($(package)_source_dir); \ + test -f $($(package)_fetched) && ( $(build_SHA256SUM) -c $($(package)_fetched) >/dev/null 2>/dev/null || \ + ( echo "Checksum missing or mismatched for $(package) source. Forcing re-download."; \ + rm -f $($(package)_all_sources) $($(1)_fetched))) || true +endef + +check-packages: + @$(foreach package,$(all_packages),$(call check_or_remove_cached,$(package));) +check-sources: + @$(foreach package,$(all_packages),$(call check_or_remove_sources,$(package));) + +$(host_prefix)/share/config.site: check-packages + +check-packages: check-sources + +install: check-packages $(host_prefix)/share/config.site + + +download-one: check-sources $(all_sources) + +download-osx: + @$(MAKE) -s HOST=x86_64-apple-darwin11 download-one +download-linux: + @$(MAKE) -s HOST=x86_64-unknown-linux-gnu download-one +download-win: + @$(MAKE) -s HOST=x86_64-w64-mingw32 download-one +download: download-osx download-linux download-win + +.PHONY: install cached download-one download-osx download-linux download-win download check-packages check-sources diff --git a/depends/README.md b/depends/README.md new file mode 100644 index 00000000..69698496 --- /dev/null +++ b/depends/README.md @@ -0,0 +1,57 @@ +### Usage + +To build dependencies for the current arch+OS: + + make + +To build for another arch/OS: + + make HOST=host-platform-triplet + +For example: + + make HOST=x86_64-w64-mingw32 -j4 + +A prefix will be generated that's suitable for plugging into Bitcoin's +configure. In the above example, a dir named x86_64-w64-mingw32 will be +created. To use it for Bitcoin: + + ./configure --prefix=`pwd`/depends/x86_64-w64-mingw32 + +Common `host-platform-triplets` for cross compilation are: + +- `i686-w64-mingw32` for Win32 +- `x86_64-w64-mingw32` for Win64 +- `x86_64-apple-darwin11` for MacOSX +- `arm-linux-gnueabihf` for Linux ARM 32 bit +- `aarch64-linux-gnu` for Linux ARM 64 bit + +No other options are needed, the paths are automatically configured. + +Dependency Options: +The following can be set when running make: make FOO=bar + + SOURCES_PATH: downloaded sources will be placed here + BASE_CACHE: built packages will be placed here + SDK_PATH: Path where sdk's can be found (used by OSX) + FALLBACK_DOWNLOAD_PATH: If a source file can't be fetched, try here before giving up + NO_QT: Don't download/build/cache qt and its dependencies + NO_WALLET: Don't download/build/cache libs needed to enable the wallet + NO_UPNP: Don't download/build/cache packages needed for enabling upnp + DEBUG: disable some optimizations and enable more runtime checking + +If some packages are not built, for example `make NO_WALLET=1`, the appropriate +options will be passed to bitcoin's configure. In this case, `--disable-wallet`. + +Additional targets: + + download: run 'make download' to fetch all sources without building them + download-osx: run 'make download-osx' to fetch all sources needed for osx builds + download-win: run 'make download-win' to fetch all sources needed for win builds + download-linux: run 'make download-linux' to fetch all sources needed for linux builds + +### Other documentation + +- [description.md](description.md): General description of the depends system +- [packages.md](packages.md): Steps for adding packages + diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk new file mode 100644 index 00000000..200d6ed2 --- /dev/null +++ b/depends/builders/darwin.mk @@ -0,0 +1,22 @@ +build_darwin_CC: = $(shell xcrun -f clang) +build_darwin_CXX: = $(shell xcrun -f clang++) +build_darwin_AR: = $(shell xcrun -f ar) +build_darwin_RANLIB: = $(shell xcrun -f ranlib) +build_darwin_STRIP: = $(shell xcrun -f strip) +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) -o + +#darwin host on darwin builder. overrides darwin host preferences. +darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) +darwin_CXX:=$(shell xcrun -f clang++) -mmacosx-version-min=$(OSX_MIN_VERSION) +darwin_AR:=$(shell xcrun -f ar) +darwin_RANLIB:=$(shell xcrun -f ranlib) +darwin_STRIP:=$(shell xcrun -f strip) +darwin_LIBTOOL:=$(shell xcrun -f libtool) +darwin_OTOOL:=$(shell xcrun -f otool) +darwin_NM:=$(shell xcrun -f nm) +darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) +darwin_native_toolchain= diff --git a/depends/builders/default.mk b/depends/builders/default.mk new file mode 100644 index 00000000..f097db65 --- /dev/null +++ b/depends/builders/default.mk @@ -0,0 +1,20 @@ +default_build_CC = gcc +default_build_CXX = g++ +default_build_AR = ar +default_build_RANLIB = ranlib +default_build_STRIP = strip +default_build_NM = nm +default_build_OTOOL = otool +default_build_INSTALL_NAME_TOOL = install_name_tool + +define add_build_tool_func +build_$(build_os)_$1 ?= $$(default_build_$1) +build_$(build_arch)_$(build_os)_$1 ?= $$(build_$(build_os)_$1) +build_$1=$$(build_$(build_arch)_$(build_os)_$1) +endef +$(foreach var,CC CXX AR RANLIB NM STRIP SHA256SUM DOWNLOAD OTOOL INSTALL_NAME_TOOL,$(eval $(call add_build_tool_func,$(var)))) +define add_build_flags_func +build_$(build_arch)_$(build_os)_$1 += $(build_$(build_os)_$1) +build_$1=$$(build_$(build_arch)_$(build_os)_$1) +endef +$(foreach flags, CFLAGS CXXFLAGS LDFLAGS, $(eval $(call add_build_flags_func,$(flags)))) diff --git a/depends/builders/linux.mk b/depends/builders/linux.mk new file mode 100644 index 00000000..b03f4240 --- /dev/null +++ b/depends/builders/linux.mk @@ -0,0 +1,2 @@ +build_linux_SHA256SUM = sha256sum +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 new file mode 100644 index 00000000..c4bd827a --- /dev/null +++ b/depends/config.guess @@ -0,0 +1,1456 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2016 Free Software Foundation, Inc. + +timestamp='2016-05-15' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# 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 +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +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." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + 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 ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + 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 ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + 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` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + 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 (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 + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + 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 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + 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 + 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 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = hppa2.0w ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + 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_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/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "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 + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +cat >&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/depends/config.site.in b/depends/config.site.in new file mode 100644 index 00000000..b19dd49d --- /dev/null +++ b/depends/config.site.in @@ -0,0 +1,101 @@ +depends_prefix="`dirname ${ac_site_file}`/.." + +cross_compiling=maybe +host_alias=@HOST@ +ac_tool_prefix=${host_alias}- + +if test -z $with_boost; then + with_boost=$depends_prefix +fi +if test -z $with_qt_plugindir; then + with_qt_plugindir=$depends_prefix/plugins +fi +if test -z $with_qt_translationdir; then + with_qt_translationdir=$depends_prefix/translations +fi +if test -z $with_qt_bindir && test -z "@no_qt@"; then + with_qt_bindir=$depends_prefix/native/bin +fi +if test -z $with_protoc_bindir && test -z "@no_qt@"; then + with_protoc_bindir=$depends_prefix/native/bin +fi + + +if test -z $enable_wallet && test -n "@no_wallet@"; then + enable_wallet=no +fi + +if test -z $with_miniupnpc && test -n "@no_upnp@"; then + with_miniupnpc=no +fi + +if test -z $with_gui && test -n "@no_qt@"; then + with_gui=no +fi + +if test x@host_os@ = xdarwin; then + BREW=no + PORT=no +fi + +if test x@host_os@ = xmingw32; then + if test -z $with_qt_incdir; then + with_qt_incdir=$depends_prefix/include + fi + if test -z $with_qt_libdir; then + with_qt_libdir=$depends_prefix/lib + fi +fi + +PATH=$depends_prefix/native/bin:$PATH +PKG_CONFIG="`which pkg-config` --static" + +# These two need to remain exported because pkg-config does not see them +# otherwise. That means they must be unexported at the end of configure.ac to +# avoid ruining the cache. Sigh. +export PKG_CONFIG_PATH=$depends_prefix/share/pkgconfig:$depends_prefix/lib/pkgconfig +if test -z "@allow_host_packages@"; then + export PKGCONFIG_LIBDIR= +fi + +CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS" +LDFLAGS="-L$depends_prefix/lib $LDFLAGS" + +CC="@CC@" +CXX="@CXX@" +OBJC="${CC}" +OBJCXX="${CXX}" +CCACHE=$depends_prefix/native/bin/ccache +PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH + +if test -n "@AR@"; then + AR=@AR@ + ac_cv_path_ac_pt_AR=${AR} +fi + +if test -n "@RANLIB@"; then + RANLIB=@RANLIB@ + ac_cv_path_ac_pt_RANLIB=${RANLIB} +fi + +if test -n "@NM@"; then + NM=@NM@ + ac_cv_path_ac_pt_NM=${NM} +fi + +if test -n "@debug@"; then + enable_reduce_exports=no +fi + +if test -n "@CFLAGS@"; then + CFLAGS="@CFLAGS@ $CFLAGS" +fi +if test -n "@CXXFLAGS@"; then + CXXFLAGS="@CXXFLAGS@ $CXXFLAGS" +fi +if test -n "@CPPFLAGS@"; then + CPPFLAGS="@CPPFLAGS@ $CPPFLAGS" +fi +if test -n "@LDFLAGS@"; then + LDFLAGS="@LDFLAGS@ $LDFLAGS" +fi diff --git a/depends/config.sub b/depends/config.sub new file mode 100644 index 00000000..6d86a1e2 --- /dev/null +++ b/depends/config.sub @@ -0,0 +1,1815 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2016 Free Software Foundation, Inc. + +timestamp='2016-05-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# 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 + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +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." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -ios) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/depends/description.md b/depends/description.md new file mode 100644 index 00000000..74f9ef3f --- /dev/null +++ b/depends/description.md @@ -0,0 +1,53 @@ +This is a system of building and caching dependencies necessary for building Bitcoin. +There are several features that make it different from most similar systems: + +### It is designed to be builder and host agnostic + +In theory, binaries for any target OS/architecture can be created, from a +builder running any OS/architecture. In practice, build-side tools must be +specified when the defaults don't fit, and packages must be amended to work +on new hosts. For now, a build architecture of x86_64 is assumed, either on +Linux or OSX. + +### No reliance on timestamps + +File presence is used to determine what needs to be built. This makes the +results distributable and easily digestable by automated builders. + +### Each build only has its specified dependencies available at build-time. + +For each build, the sysroot is wiped and the (recursive) dependencies are +installed. This makes each build deterministic, since there will never be any +unknown files available to cause side-effects. + +### Each package is cached and only rebuilt as needed. + +Before building, a unique build-id is generated for each package. This id +consists of a hash of all files used to build the package (Makefiles, packages, +etc), and as well as a hash of the same data for each recursive dependency. If +any portion of a package's build recipe changes, it will be rebuilt as well as +any other package that depends on it. If any of the main makefiles (Makefile, +funcs.mk, etc) are changed, all packages will be rebuilt. After building, the +results are cached into a tarball that can be re-used and distributed. + +### Package build results are (relatively) deterministic. + +Each package is configured and patched so that it will yield the same +build-results with each consequent build, within a reasonable set of +constraints. Some things like timestamp insertion are unavoidable, and are +beyond the scope of this system. Additionally, the toolchain itself must be +capable of deterministic results. When revisions are properly bumped, a cached +build should represent an exact single payload. + +### Sources are fetched and verified automatically + +Each package must define its source location and checksum. The build will fail +if the fetched source does not match. Sources may be pre-seeded and/or cached +as desired. + +### Self-cleaning + +Build and staging dirs are wiped after use, and any previous version of a +cached result is removed following a successful build. Automated builders +should be able to build each revision and store the results with no further +intervention. diff --git a/depends/funcs.mk b/depends/funcs.mk new file mode 100644 index 00000000..050a9b13 --- /dev/null +++ b/depends/funcs.mk @@ -0,0 +1,241 @@ +define int_vars +#Set defaults for vars which may be overridden per-package +$(1)_cc=$($($(1)_type)_CC) +$(1)_cxx=$($($(1)_type)_CXX) +$(1)_objc=$($($(1)_type)_OBJC) +$(1)_objcxx=$($($(1)_type)_OBJCXX) +$(1)_ar=$($($(1)_type)_AR) +$(1)_ranlib=$($($(1)_type)_RANLIB) +$(1)_libtool=$($($(1)_type)_LIBTOOL) +$(1)_nm=$($($(1)_type)_NM) +$(1)_cflags=$($($(1)_type)_CFLAGS) $($($(1)_type)_$(release_type)_CFLAGS) +$(1)_cxxflags=$($($(1)_type)_CXXFLAGS) $($($(1)_type)_$(release_type)_CXXFLAGS) +$(1)_ldflags=$($($(1)_type)_LDFLAGS) $($($(1)_type)_$(release_type)_LDFLAGS) -L$($($(1)_type)_prefix)/lib +$(1)_cppflags=$($($(1)_type)_CPPFLAGS) $($($(1)_type)_$(release_type)_CPPFLAGS) -I$($($(1)_type)_prefix)/include +$(1)_recipe_hash:= +endef + +define int_get_all_dependencies +$(sort $(foreach dep,$(2),$(2) $(call int_get_all_dependencies,$(1),$($(dep)_dependencies)))) +endef + +define fetch_file +(test -f $$($(1)_source_dir)/$(4) || \ + ( mkdir -p $$($(1)_download_dir) && echo Fetching $(1)... && \ + ( $(build_DOWNLOAD) "$$($(1)_download_dir)/$(4).temp" "$(2)/$(3)" || \ + $(build_DOWNLOAD) "$$($(1)_download_dir)/$(4).temp" "$(FALLBACK_DOWNLOAD_PATH)/$(3)" ) && \ + echo "$(5) $$($(1)_download_dir)/$(4).temp" > $$($(1)_download_dir)/.$(4).hash && \ + $(build_SHA256SUM) -c $$($(1)_download_dir)/.$(4).hash && \ + mv $$($(1)_download_dir)/$(4).temp $$($(1)_source_dir)/$(4) && \ + rm -rf $$($(1)_download_dir) )) +endef + +define int_get_build_recipe_hash +$(eval $(1)_all_file_checksums:=$(shell $(build_SHA256SUM) $(meta_depends) packages/$(1).mk $(addprefix $(PATCHES_PATH)/$(1)/,$($(1)_patches)) | cut -d" " -f1)) +$(eval $(1)_recipe_hash:=$(shell echo -n "$($(1)_all_file_checksums)" | $(build_SHA256SUM) | cut -d" " -f1)) +endef + +define int_get_build_id +$(eval $(1)_dependencies += $($(1)_$(host_arch)_$(host_os)_dependencies) $($(1)_$(host_os)_dependencies)) +$(eval $(1)_all_dependencies:=$(call int_get_all_dependencies,$(1),$($($(1)_type)_native_toolchain) $($(1)_dependencies))) +$(foreach dep,$($(1)_all_dependencies),$(eval $(1)_build_id_deps+=$(dep)-$($(dep)_version)-$($(dep)_recipe_hash))) +$(eval $(1)_build_id_long:=$(1)-$($(1)_version)-$($(1)_recipe_hash)-$(release_type) $($(1)_build_id_deps)) +$(eval $(1)_build_id:=$(shell echo -n "$($(1)_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH))) +final_build_id_long+=$($(package)_build_id_long) + +#compute package-specific paths +$(1)_build_subdir?=. +$(1)_download_file?=$($(1)_file_name) +$(1)_source_dir:=$(SOURCES_PATH) +$(1)_source:=$$($(1)_source_dir)/$($(1)_file_name) +$(1)_staging_dir=$(base_staging_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id) +$(1)_staging_prefix_dir:=$$($(1)_staging_dir)$($($(1)_type)_prefix) +$(1)_extract_dir:=$(base_build_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id) +$(1)_download_dir:=$(base_download_dir)/$(1)-$($(1)_version) +$(1)_build_dir:=$$($(1)_extract_dir)/$$($(1)_build_subdir) +$(1)_cached_checksum:=$(BASE_CACHE)/$(host)/$(1)/$(1)-$($(1)_version)-$($(1)_build_id).tar.gz.hash +$(1)_patch_dir:=$(base_build_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id)/.patches-$($(1)_build_id) +$(1)_prefixbin:=$($($(1)_type)_prefix)/bin/ +$(1)_cached:=$(BASE_CACHE)/$(host)/$(1)/$(1)-$($(1)_version)-$($(1)_build_id).tar.gz +$(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources) + +#stamps +$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_file_name).hash +$(1)_extracted=$$($(1)_extract_dir)/.stamp_extracted +$(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed +$(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned +$(1)_built=$$($(1)_build_dir)/.stamp_built +$(1)_configured=$$($(1)_build_dir)/.stamp_configured +$(1)_staged=$$($(1)_staging_dir)/.stamp_staged +$(1)_postprocessed=$$($(1)_staging_prefix_dir)/.stamp_postprocessed +$(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path)) + + +#default commands +$(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash)) +$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --strip-components=1 -xf $$($(1)_source) +$(1)_preprocess_cmds ?= +$(1)_build_cmds ?= +$(1)_config_cmds ?= +$(1)_stage_cmds ?= +$(1)_set_vars ?= + + +all_sources+=$$($(1)_fetched) +endef +#$(foreach dep_target,$($(1)_all_dependencies),$(eval $(1)_dependency_targets=$($(dep_target)_cached))) + + +define int_config_attach_build_config +$(eval $(call $(1)_set_vars,$(1))) +$(1)_cflags+=$($(1)_cflags_$(release_type)) +$(1)_cflags+=$($(1)_cflags_$(host_arch)) $($(1)_cflags_$(host_arch)_$(release_type)) +$(1)_cflags+=$($(1)_cflags_$(host_os)) $($(1)_cflags_$(host_os)_$(release_type)) +$(1)_cflags+=$($(1)_cflags_$(host_arch)_$(host_os)) $($(1)_cflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_cxxflags+=$($(1)_cxxflags_$(release_type)) +$(1)_cxxflags+=$($(1)_cxxflags_$(host_arch)) $($(1)_cxxflags_$(host_arch)_$(release_type)) +$(1)_cxxflags+=$($(1)_cxxflags_$(host_os)) $($(1)_cxxflags_$(host_os)_$(release_type)) +$(1)_cxxflags+=$($(1)_cxxflags_$(host_arch)_$(host_os)) $($(1)_cxxflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_cppflags+=$($(1)_cppflags_$(release_type)) +$(1)_cppflags+=$($(1)_cppflags_$(host_arch)) $($(1)_cppflags_$(host_arch)_$(release_type)) +$(1)_cppflags+=$($(1)_cppflags_$(host_os)) $($(1)_cppflags_$(host_os)_$(release_type)) +$(1)_cppflags+=$($(1)_cppflags_$(host_arch)_$(host_os)) $($(1)_cppflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_ldflags+=$($(1)_ldflags_$(release_type)) +$(1)_ldflags+=$($(1)_ldflags_$(host_arch)) $($(1)_ldflags_$(host_arch)_$(release_type)) +$(1)_ldflags+=$($(1)_ldflags_$(host_os)) $($(1)_ldflags_$(host_os)_$(release_type)) +$(1)_ldflags+=$($(1)_ldflags_$(host_arch)_$(host_os)) $($(1)_ldflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_build_opts+=$$($(1)_build_opts_$(release_type)) +$(1)_build_opts+=$$($(1)_build_opts_$(host_arch)) $$($(1)_build_opts_$(host_arch)_$(release_type)) +$(1)_build_opts+=$$($(1)_build_opts_$(host_os)) $$($(1)_build_opts_$(host_os)_$(release_type)) +$(1)_build_opts+=$$($(1)_build_opts_$(host_arch)_$(host_os)) $$($(1)_build_opts_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_config_opts+=$$($(1)_config_opts_$(release_type)) +$(1)_config_opts+=$$($(1)_config_opts_$(host_arch)) $$($(1)_config_opts_$(host_arch)_$(release_type)) +$(1)_config_opts+=$$($(1)_config_opts_$(host_os)) $$($(1)_config_opts_$(host_os)_$(release_type)) +$(1)_config_opts+=$$($(1)_config_opts_$(host_arch)_$(host_os)) $$($(1)_config_opts_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_config_env+=$$($(1)_config_env_$(release_type)) +$(1)_config_env+=$($(1)_config_env_$(host_arch)) $($(1)_config_env_$(host_arch)_$(release_type)) +$(1)_config_env+=$($(1)_config_env_$(host_os)) $($(1)_config_env_$(host_os)_$(release_type)) +$(1)_config_env+=$($(1)_config_env_$(host_arch)_$(host_os)) $($(1)_config_env_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_config_env+=PKG_CONFIG_LIBDIR=$($($(1)_type)_prefix)/lib/pkgconfig +$(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig +$(1)_config_env+=PATH=$(build_prefix)/bin:$(PATH) +$(1)_build_env+=PATH=$(build_prefix)/bin:$(PATH) +$(1)_stage_env+=PATH=$(build_prefix)/bin:$(PATH) +$(1)_autoconf=./configure --host=$($($(1)_type)_host) --disable-dependency-tracking --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)" + +ifneq ($($(1)_nm),) +$(1)_autoconf += NM="$$($(1)_nm)" +endif +ifneq ($($(1)_ranlib),) +$(1)_autoconf += RANLIB="$$($(1)_ranlib)" +endif +ifneq ($($(1)_ar),) +$(1)_autoconf += AR="$$($(1)_ar)" +endif +ifneq ($($(1)_cflags),) +$(1)_autoconf += CFLAGS="$$($(1)_cflags)" +endif +ifneq ($($(1)_cxxflags),) +$(1)_autoconf += CXXFLAGS="$$($(1)_cxxflags)" +endif +ifneq ($($(1)_cppflags),) +$(1)_autoconf += CPPFLAGS="$$($(1)_cppflags)" +endif +ifneq ($($(1)_ldflags),) +$(1)_autoconf += LDFLAGS="$$($(1)_ldflags)" +endif +endef + +define int_add_cmds +$($(1)_fetched): + $(AT)mkdir -p $$(@D) $(SOURCES_PATH) + $(AT)rm -f $$@ + $(AT)touch $$@ + $(AT)cd $$(@D); $(call $(1)_fetch_cmds,$(1)) + $(AT)cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);) + $(AT)touch $$@ +$($(1)_extracted): | $($(1)_fetched) + $(AT)echo Extracting $(1)... + $(AT)mkdir -p $$(@D) + $(AT)cd $$(@D); $(call $(1)_extract_cmds,$(1)) + $(AT)touch $$@ +$($(1)_preprocessed): | $($(1)_dependencies) $($(1)_extracted) + $(AT)echo Preprocessing $(1)... + $(AT)mkdir -p $$(@D) $($(1)_patch_dir) + $(AT)$(foreach patch,$($(1)_patches),cd $(PATCHES_PATH)/$(1); cp $(patch) $($(1)_patch_dir) ;) + $(AT)cd $$(@D); $(call $(1)_preprocess_cmds, $(1)) + $(AT)touch $$@ +$($(1)_configured): | $($(1)_preprocessed) + $(AT)echo Configuring $(1)... + $(AT)rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), tar xf $($(package)_cached); ) + $(AT)mkdir -p $$(@D) + $(AT)+cd $$(@D); $($(1)_config_env) $(call $(1)_config_cmds, $(1)) + $(AT)touch $$@ +$($(1)_built): | $($(1)_configured) + $(AT)echo Building $(1)... + $(AT)mkdir -p $$(@D) + $(AT)+cd $$(@D); $($(1)_build_env) $(call $(1)_build_cmds, $(1)) + $(AT)touch $$@ +$($(1)_staged): | $($(1)_built) + $(AT)echo Staging $(1)... + $(AT)mkdir -p $($(1)_staging_dir)/$(host_prefix) + $(AT)cd $($(1)_build_dir); $($(1)_stage_env) $(call $(1)_stage_cmds, $(1)) + $(AT)rm -rf $($(1)_extract_dir) + $(AT)touch $$@ +$($(1)_postprocessed): | $($(1)_staged) + $(AT)echo Postprocessing $(1)... + $(AT)cd $($(1)_staging_prefix_dir); $(call $(1)_postprocess_cmds) + $(AT)touch $$@ +$($(1)_cached): | $($(1)_dependencies) $($(1)_postprocessed) + $(AT)echo Caching $(1)... + $(AT)cd $$($(1)_staging_dir)/$(host_prefix); find . | sort | tar --no-recursion -czf $$($(1)_staging_dir)/$$(@F) -T - + $(AT)mkdir -p $$(@D) + $(AT)rm -rf $$(@D) && mkdir -p $$(@D) + $(AT)mv $$($(1)_staging_dir)/$$(@F) $$(@) + $(AT)rm -rf $($(1)_staging_dir) +$($(1)_cached_checksum): $($(1)_cached) + $(AT)cd $$(@D); $(build_SHA256SUM) $$( $$(@) + +.PHONY: $(1) +$(1): | $($(1)_cached_checksum) +.SECONDARY: $($(1)_cached) $($(1)_postprocessed) $($(1)_staged) $($(1)_built) $($(1)_configured) $($(1)_preprocessed) $($(1)_extracted) $($(1)_fetched) + +endef + +# These functions create the build targets for each package. They must be +# broken down into small steps so that each part is done for all packages +# before moving on to the next step. Otherwise, a package's info +# (build-id for example) would only be available to another package if it +# happened to be computed already. + +#set the type for host/build packages. +$(foreach native_package,$(native_packages),$(eval $(native_package)_type=build)) +$(foreach package,$(packages),$(eval $(package)_type=$(host_arch)_$(host_os))) + +#set overridable defaults +$(foreach package,$(all_packages),$(eval $(call int_vars,$(package)))) + +#include package files +$(foreach package,$(all_packages),$(eval include packages/$(package).mk)) + +#compute a hash of all files that comprise this package's build recipe +$(foreach package,$(all_packages),$(eval $(call int_get_build_recipe_hash,$(package)))) + +#generate a unique id for this package, incorporating its dependencies as well +$(foreach package,$(all_packages),$(eval $(call int_get_build_id,$(package)))) + +#compute final vars after reading package vars +$(foreach package,$(all_packages),$(eval $(call int_config_attach_build_config,$(package)))) + +#create build targets +$(foreach package,$(all_packages),$(eval $(call int_add_cmds,$(package)))) + +#special exception: if a toolchain package exists, all non-native packages depend on it +$(foreach package,$(packages),$(eval $($(package)_unpacked): |$($($(host_arch)_$(host_os)_native_toolchain)_cached) )) diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk new file mode 100644 index 00000000..98564961 --- /dev/null +++ b/depends/hosts/darwin.mk @@ -0,0 +1,17 @@ +OSX_MIN_VERSION=10.7 +OSX_SDK_VERSION=10.11 +OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk +LD64_VERSION=253.9 +darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) +darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -stdlib=libc++ + +darwin_CFLAGS=-pipe +darwin_CXXFLAGS=$(darwin_CFLAGS) + +darwin_release_CFLAGS=-O2 +darwin_release_CXXFLAGS=$(darwin_release_CFLAGS) + +darwin_debug_CFLAGS=-O1 +darwin_debug_CXXFLAGS=$(darwin_debug_CFLAGS) + +darwin_native_toolchain=native_cctools diff --git a/depends/hosts/default.mk b/depends/hosts/default.mk new file mode 100644 index 00000000..6f60d6b3 --- /dev/null +++ b/depends/hosts/default.mk @@ -0,0 +1,26 @@ +default_host_CC = $(host_toolchain)gcc +default_host_CXX = $(host_toolchain)g++ +default_host_AR = $(host_toolchain)ar +default_host_RANLIB = $(host_toolchain)ranlib +default_host_STRIP = $(host_toolchain)strip +default_host_LIBTOOL = $(host_toolchain)libtool +default_host_INSTALL_NAME_TOOL = $(host_toolchain)install_name_tool +default_host_OTOOL = $(host_toolchain)otool +default_host_NM = $(host_toolchain)nm + +define add_host_tool_func +$(host_os)_$1?=$$(default_host_$1) +$(host_arch)_$(host_os)_$1?=$$($(host_os)_$1) +$(host_arch)_$(host_os)_$(release_type)_$1?=$$($(host_os)_$1) +host_$1=$$($(host_arch)_$(host_os)_$1) +endef + +define add_host_flags_func +$(host_arch)_$(host_os)_$1 += $($(host_os)_$1) +$(host_arch)_$(host_os)_$(release_type)_$1 += $($(host_os)_$(release_type)_$1) +host_$1 = $$($(host_arch)_$(host_os)_$1) +host_$(release_type)_$1 = $$($(host_arch)_$(host_os)_$(release_type)_$1) +endef + +$(foreach tool,CC CXX AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL,$(eval $(call add_host_tool_func,$(tool)))) +$(foreach flags,CFLAGS CXXFLAGS CPPFLAGS LDFLAGS, $(eval $(call add_host_flags_func,$(flags)))) diff --git a/depends/hosts/linux.mk b/depends/hosts/linux.mk new file mode 100644 index 00000000..b13a0f1a --- /dev/null +++ b/depends/hosts/linux.mk @@ -0,0 +1,31 @@ +linux_CFLAGS=-pipe +linux_CXXFLAGS=$(linux_CFLAGS) + +linux_release_CFLAGS=-O2 +linux_release_CXXFLAGS=$(linux_release_CFLAGS) + +linux_debug_CFLAGS=-O1 +linux_debug_CXXFLAGS=$(linux_debug_CFLAGS) + +linux_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC + +ifeq (86,$(findstring 86,$(build_arch))) +i686_linux_CC=gcc -m32 +i686_linux_CXX=g++ -m32 +i686_linux_AR=ar +i686_linux_RANLIB=ranlib +i686_linux_NM=nm +i686_linux_STRIP=strip + +x86_64_linux_CC=gcc -m64 +x86_64_linux_CXX=g++ -m64 +x86_64_linux_AR=ar +x86_64_linux_RANLIB=ranlib +x86_64_linux_NM=nm +x86_64_linux_STRIP=strip +else +i686_linux_CC=$(default_host_CC) -m32 +i686_linux_CXX=$(default_host_CXX) -m32 +x86_64_linux_CC=$(default_host_CC) -m64 +x86_64_linux_CXX=$(default_host_CXX) -m64 +endif diff --git a/depends/hosts/mingw32.mk b/depends/hosts/mingw32.mk new file mode 100644 index 00000000..dbfb62fd --- /dev/null +++ b/depends/hosts/mingw32.mk @@ -0,0 +1,10 @@ +mingw32_CFLAGS=-pipe +mingw32_CXXFLAGS=$(mingw32_CFLAGS) + +mingw32_release_CFLAGS=-O2 +mingw32_release_CXXFLAGS=$(mingw32_release_CFLAGS) + +mingw32_debug_CFLAGS=-O1 +mingw32_debug_CXXFLAGS=$(mingw32_debug_CFLAGS) + +mingw32_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC diff --git a/depends/packages.md b/depends/packages.md new file mode 100644 index 00000000..7c803625 --- /dev/null +++ b/depends/packages.md @@ -0,0 +1,147 @@ +Each recipe consists of 3 main parts: defining identifiers, setting build +variables, and defining build commands. + +The package "mylib" will be used here as an example + +General tips: +- mylib_foo is written as $(package)_foo in order to make recipes more similar. + +## Identifiers +Each package is required to define at least these variables: + + $(package)_version: + Version of the upstream library or program. If there is no version, a + placeholder such as 1.0 can be used. + + $(package)_download_path: + Location of the upstream source, without the file-name. Usually http or + ftp. + + $(package)_file_name: + The upstream source filename available at the download path. + + $(package)_sha256_hash: + The sha256 hash of the upstream file + +These variables are optional: + + $(package)_build_subdir: + cd to this dir before running configure/build/stage commands. + + $(package)_download_file: + The file-name of the upstream source if it differs from how it should be + stored locally. This can be used to avoid storing file-names with strange + characters. + + $(package)_dependencies: + Names of any other packages that this one depends on. + + $(package)_patches: + Filenames of any patches needed to build the package + + $(package)_extra_sources: + Any extra files that will be fetched via $(package)_fetch_cmds. These are + specified so that they can be fetched and verified via 'make download'. + + +## Build Variables: +After defining the main identifiers, build variables may be added or customized +before running the build commands. They should be added to a function called +$(package)_set_vars. For example: + + define $(package)_set_vars + ... + endef + +Most variables can be prefixed with the host, architecture, or both, to make +the modifications specific to that case. For example: + + Universal: $(package)_cc=gcc + Linux only: $(package)_linux_cc=gcc + x86_64 only: $(package)_x86_64_cc = gcc + x86_64 linux only: $(package)_x86_64_linux_cc = gcc + +These variables may be set to override or append their default values. + + $(package)_cc + $(package)_cxx + $(package)_objc + $(package)_objcxx + $(package)_ar + $(package)_ranlib + $(package)_libtool + $(package)_nm + $(package)_cflags + $(package)_cxxflags + $(package)_ldflags + $(package)_cppflags + $(package)_config_env + $(package)_build_env + $(package)_stage_env + $(package)_build_opts + $(package)_config_opts + +The *_env variables are used to add environment variables to the respective +commands. + +Many variables respect a debug/release suffix as well, in order to use them for +only the appropriate build config. For example: + + $(package)_cflags_release = -O3 + $(package)_cflags_i686_debug = -g + $(package)_config_opts_release = --disable-debug + +These will be used in addition to the options that do not specify +debug/release. All builds are considered to be release unless DEBUG=1 is set by +the user. Other variables may be defined as needed. + +## Build commands: + + For each build, a unique build dir and staging dir are created. For example, + `work/build/mylib/1.0-1adac830f6e` and `work/staging/mylib/1.0-1adac830f6e`. + + The following build commands are available for each recipe: + + $(package)_fetch_cmds: + Runs from: build dir + Fetch the source file. If undefined, it will be fetched and verified + against its hash. + + $(package)_extract_cmds: + Runs from: build dir + Verify the source file against its hash and extract it. If undefined, the + source is assumed to be a tarball. + + $(package)_preprocess_cmds: + Runs from: build dir/$(package)_build_subdir + Preprocess the source as necessary. If undefined, does nothing. + + $(package)_config_cmds: + Runs from: build dir/$(package)_build_subdir + Configure the source. If undefined, does nothing. + + $(package)_build_cmds: + Runs from: build dir/$(package)_build_subdir + Build the source. If undefined, does nothing. + + $(package)_stage_cmds: + Runs from: build dir/$(package)_build_subdir + Stage the build results. If undefined, does nothing. + + The following variables are available for each recipe: + + $(1)_staging_dir: package's destination sysroot path + $(1)_staging_prefix_dir: prefix path inside of the package's staging dir + $(1)_extract_dir: path to the package's extracted sources + $(1)_build_dir: path where configure/build/stage commands will be run + $(1)_patch_dir: path where the package's patches (if any) are found + +Notes on build commands: + +For packages built with autotools, $($(package)_autoconf) can be used in the +configure step to (usually) correctly configure automatically. Any +$($(package)_config_opts) will be appended. + +Most autotools projects can be properly staged using: + + $(MAKE) DESTDIR=$($(package)_staging_dir) install diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk new file mode 100644 index 00000000..e2b73b62 --- /dev/null +++ b/depends/packages/bdb.mk @@ -0,0 +1,32 @@ +package=bdb +$(package)_version=4.8.30 +$(package)_download_path=http://download.oracle.com/berkeley-db +$(package)_file_name=db-$($(package)_version).NC.tar.gz +$(package)_sha256_hash=12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef +$(package)_build_subdir=build_unix + +define $(package)_set_vars +$(package)_config_opts=--disable-shared --enable-cxx --disable-replication +$(package)_config_opts_mingw32=--enable-mingw +$(package)_config_opts_linux=--with-pic +$(package)_cxxflags=-std=c++11 +endef + +define $(package)_preprocess_cmds + sed -i.old 's/__atomic_compare_exchange/__atomic_compare_exchange_db/' dbinc/atomic.h && \ + sed -i.old 's/atomic_init/atomic_init_db/' dbinc/atomic.h mp/mp_region.c mp/mp_mvcc.c mp/mp_fget.c mutex/mut_method.c mutex/mut_tas.c && \ + cp -f $(BASEDIR)/config.guess dist && \ + cp -f $(BASEDIR)/config.sub dist +endef + +define $(package)_config_cmds + ../dist/$($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) libdb_cxx-4.8.a libdb-4.8.a +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install_lib install_include +endef diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk new file mode 100644 index 00000000..4173c0d1 --- /dev/null +++ b/depends/packages/boost.mk @@ -0,0 +1,41 @@ +package=boost +$(package)_version=1_61_0 +$(package)_download_path=https://sourceforge.net/projects/boost/files/boost/1.61.0 +$(package)_file_name=$(package)_$($(package)_version).tar.bz2 +$(package)_sha256_hash=a547bd06c2fd9a71ba1d169d9cf0339da7ebf4753849a8f7d6fdb8feee99b640 + +define $(package)_set_vars +$(package)_config_opts_release=variant=release +$(package)_config_opts_debug=variant=debug +$(package)_config_opts=--layout=tagged --build-type=complete --user-config=user-config.jam +$(package)_config_opts+=threading=multi link=static -sNO_BZIP2=1 -sNO_ZLIB=1 +$(package)_config_opts_linux=threadapi=pthread runtime-link=shared +$(package)_config_opts_darwin=--toolset=darwin-4.2.1 runtime-link=shared +$(package)_config_opts_mingw32=binary-format=pe target-os=windows threadapi=win32 runtime-link=static +$(package)_config_opts_x86_64_mingw32=address-model=64 +$(package)_config_opts_i686_mingw32=address-model=32 +$(package)_config_opts_i686_linux=address-model=32 architecture=x86 +$(package)_toolset_$(host_os)=gcc +$(package)_archiver_$(host_os)=$($(package)_ar) +$(package)_toolset_darwin=darwin +$(package)_archiver_darwin=$($(package)_libtool) +$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test +$(package)_cxxflags=-std=c++11 -fvisibility=hidden +$(package)_cxxflags_linux=-fPIC +endef + +define $(package)_preprocess_cmds + echo "using $(boost_toolset_$(host_os)) : : $($(package)_cxx) : \"$($(package)_cxxflags) $($(package)_cppflags)\" \"$($(package)_ldflags)\" \"$(boost_archiver_$(host_os))\" \"$(host_STRIP)\" \"$(host_RANLIB)\" \"$(host_WINDRES)\" : ;" > user-config.jam +endef + +define $(package)_config_cmds + ./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries) +endef + +define $(package)_build_cmds + ./b2 -d2 -j2 -d1 --prefix=$($(package)_staging_prefix_dir) $($(package)_config_opts) stage +endef + +define $(package)_stage_cmds + ./b2 -d0 -j4 --prefix=$($(package)_staging_prefix_dir) $($(package)_config_opts) install +endef diff --git a/depends/packages/dbus.mk b/depends/packages/dbus.mk new file mode 100644 index 00000000..8ac9ab74 --- /dev/null +++ b/depends/packages/dbus.mk @@ -0,0 +1,23 @@ +package=dbus +$(package)_version=1.8.6 +$(package)_download_path=http://dbus.freedesktop.org/releases/dbus +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=eded83ca007b719f32761e60fd8b9ffd0f5796a4caf455b01b5a5ef740ebd23f +$(package)_dependencies=expat + +define $(package)_set_vars + $(package)_config_opts=--disable-tests --disable-doxygen-docs --disable-xml-docs --disable-static --without-x +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) -C dbus libdbus-1.la +endef + +define $(package)_stage_cmds + $(MAKE) -C dbus DESTDIR=$($(package)_staging_dir) install-libLTLIBRARIES install-dbusincludeHEADERS install-nodist_dbusarchincludeHEADERS && \ + $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA +endef diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk new file mode 100644 index 00000000..1ac44353 --- /dev/null +++ b/depends/packages/expat.mk @@ -0,0 +1,21 @@ +package=expat +$(package)_version=2.1.0 +$(package)_download_path=http://sourceforge.net/projects/expat/files/expat/$($(package)_version) +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=823705472f816df21c8f6aa026dd162b280806838bb55b3432b0fb1fcca7eb86 + +define $(package)_set_vars +$(package)_config_opts=--disable-static +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/fontconfig.mk b/depends/packages/fontconfig.mk new file mode 100644 index 00000000..2cf553ed --- /dev/null +++ b/depends/packages/fontconfig.mk @@ -0,0 +1,22 @@ +package=fontconfig +$(package)_version=2.11.1 +$(package)_download_path=http://www.freedesktop.org/software/fontconfig/release/ +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=dc62447533bca844463a3c3fd4083b57c90f18a70506e7a9f4936b5a1e516a99 +$(package)_dependencies=freetype expat + +define $(package)_set_vars + $(package)_config_opts=--disable-docs --disable-static +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk new file mode 100644 index 00000000..f7d6e0f9 --- /dev/null +++ b/depends/packages/freetype.mk @@ -0,0 +1,22 @@ +package=freetype +$(package)_version=2.5.3 +$(package)_download_path=http://downloads.sourceforge.net/$(package) +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=c0848b29d52ef3ca27ad92e08351f023c5e24ce8cea7d8fe69fc96358e65f75e + +define $(package)_set_vars + $(package)_config_opts=--without-zlib --without-png --disable-static + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/libICE.mk b/depends/packages/libICE.mk new file mode 100644 index 00000000..fc60323b --- /dev/null +++ b/depends/packages/libICE.mk @@ -0,0 +1,23 @@ +package=libICE +$(package)_version=1.0.9 +$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=8f7032f2c1c64352b5423f6b48a8ebdc339cc63064af34d66a6c9aa79759e202 +$(package)_dependencies=xtrans xproto + +define $(package)_set_vars + $(package)_config_opts=--disable-static --disable-docs --disable-specs --without-xsltproc + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/libSM.mk b/depends/packages/libSM.mk new file mode 100644 index 00000000..0f9307ca --- /dev/null +++ b/depends/packages/libSM.mk @@ -0,0 +1,23 @@ +package=libSM +$(package)_version=1.2.2 +$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=0baca8c9f5d934450a70896c4ad38d06475521255ca63b717a6510fdb6e287bd +$(package)_dependencies=xtrans xproto libICE + +define $(package)_set_vars + $(package)_config_opts=--without-libuuid --without-xsltproc --disable-docs --disable-static + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/libX11.mk b/depends/packages/libX11.mk new file mode 100644 index 00000000..178d592e --- /dev/null +++ b/depends/packages/libX11.mk @@ -0,0 +1,23 @@ +package=libX11 +$(package)_version=1.6.2 +$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=2aa027e837231d2eeea90f3a4afe19948a6eb4c8b2bec0241eba7dbc8106bd16 +$(package)_dependencies=libxcb xtrans xextproto xproto + +define $(package)_set_vars +$(package)_config_opts=--disable-xkb --disable-static +$(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/libXau.mk b/depends/packages/libXau.mk new file mode 100644 index 00000000..e87df2e4 --- /dev/null +++ b/depends/packages/libXau.mk @@ -0,0 +1,23 @@ +package=libXau +$(package)_version=1.0.8 +$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=fdd477320aeb5cdd67272838722d6b7d544887dfe7de46e1e7cc0c27c2bea4f2 +$(package)_dependencies=xproto + +define $(package)_set_vars + $(package)_config_opts=--disable-shared + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/libXext.mk b/depends/packages/libXext.mk new file mode 100644 index 00000000..4db83606 --- /dev/null +++ b/depends/packages/libXext.mk @@ -0,0 +1,22 @@ +package=libXext +$(package)_version=1.3.2 +$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=f829075bc646cdc085fa25d98d5885d83b1759ceb355933127c257e8e50432e0 +$(package)_dependencies=xproto xextproto libX11 libXau + +define $(package)_set_vars + $(package)_config_opts=--disable-static +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk new file mode 100644 index 00000000..2e9be1e9 --- /dev/null +++ b/depends/packages/libevent.mk @@ -0,0 +1,31 @@ +package=libevent +$(package)_version=2.0.22 +$(package)_download_path=https://github.com/libevent/libevent/releases/download/release-2.0.22-stable +$(package)_file_name=$(package)-$($(package)_version)-stable.tar.gz +$(package)_sha256_hash=71c2c49f0adadacfdbe6332a372c38cf9c8b7895bb73dabeaa53cdcc1d4e1fa3 +$(package)_patches=reuseaddr.patch + +define $(package)_preprocess_cmds + patch -p1 < $($(package)_patch_dir)/reuseaddr.patch +endef + +define $(package)_set_vars + $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress + $(package)_config_opts_release=--disable-debug-mode + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds +endef diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk new file mode 100644 index 00000000..28f2bd6f --- /dev/null +++ b/depends/packages/libxcb.mk @@ -0,0 +1,35 @@ +package=libxcb +$(package)_version=1.10 +$(package)_download_path=http://xcb.freedesktop.org/dist +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=98d9ab05b636dd088603b64229dd1ab2d2cc02ab807892e107d674f9c3f2d5b5 +$(package)_dependencies=xcb_proto libXau xproto + +define $(package)_set_vars +$(package)_config_opts=--disable-static +endef + +define $(package)_preprocess_cmds + sed "s/pthread-stubs//" -i configure +endef + +# Don't install xcb headers to the default path in order to work around a qt +# build issue: https://bugreports.qt.io/browse/QTBUG-34748 +# When using qt's internal libxcb, it may end up finding the real headers in +# depends staging. Use a non-default path to avoid that. + +define $(package)_config_cmds + $($(package)_autoconf) --includedir=$(host_prefix)/include/xcb-shared +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm -rf share/man share/doc +endef diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk new file mode 100644 index 00000000..1bb8cb5d --- /dev/null +++ b/depends/packages/miniupnpc.mk @@ -0,0 +1,28 @@ +package=miniupnpc +$(package)_version=2.0.20170509 +$(package)_download_path=http://miniupnp.free.fr/files +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=d3c368627f5cdfb66d3ebd64ca39ba54d6ff14a61966dbecb8dd296b7039f16a + +define $(package)_set_vars +$(package)_build_opts=CC="$($(package)_cc)" +$(package)_build_opts_darwin=OS=Darwin LIBTOOL="$($(package)_libtool)" +$(package)_build_opts_mingw32=-f Makefile.mingw +$(package)_build_env+=CFLAGS="$($(package)_cflags) $($(package)_cppflags)" AR="$($(package)_ar)" +endef + +define $(package)_preprocess_cmds + mkdir dll && \ + sed -e 's|MINIUPNPC_VERSION_STRING \"version\"|MINIUPNPC_VERSION_STRING \"$($(package)_version)\"|' -e 's|OS/version|$(host)|' miniupnpcstrings.h.in > miniupnpcstrings.h && \ + sed -i.old "s|miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings|miniupnpcstrings.h: miniupnpcstrings.h.in|" Makefile.mingw +endef + +define $(package)_build_cmds + $(MAKE) libminiupnpc.a $($(package)_build_opts) +endef + +define $(package)_stage_cmds + mkdir -p $($(package)_staging_prefix_dir)/include/miniupnpc $($(package)_staging_prefix_dir)/lib &&\ + install *.h $($(package)_staging_prefix_dir)/include/miniupnpc &&\ + install libminiupnpc.a $($(package)_staging_prefix_dir)/lib +endef diff --git a/depends/packages/native_biplist.mk b/depends/packages/native_biplist.mk new file mode 100644 index 00000000..eb8672d5 --- /dev/null +++ b/depends/packages/native_biplist.mk @@ -0,0 +1,15 @@ +package=native_biplist +$(package)_version=0.9 +$(package)_download_path=https://pypi.python.org/packages/source/b/biplist +$(package)_file_name=biplist-$($(package)_version).tar.gz +$(package)_sha256_hash=b57cadfd26e4754efdf89e9e37de87885f9b5c847b2615688ca04adfaf6ca604 +$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages + +define $(package)_build_cmds + python setup.py build +endef + +define $(package)_stage_cmds + mkdir -p $($(package)_install_libdir) && \ + python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) +endef diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk new file mode 100644 index 00000000..02717447 --- /dev/null +++ b/depends/packages/native_ccache.mk @@ -0,0 +1,25 @@ +package=native_ccache +$(package)_version=3.2.4 +$(package)_download_path=https://samba.org/ftp/ccache +$(package)_file_name=ccache-$($(package)_version).tar.bz2 +$(package)_sha256_hash=ffeb967edb549e67da0bd5f44f729a2022de9fdde65dfd80d2a7204d7f75332e + +define $(package)_set_vars +$(package)_config_opts= +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm -rf lib include +endef diff --git a/depends/packages/native_cctools.mk b/depends/packages/native_cctools.mk new file mode 100644 index 00000000..a621ddd5 --- /dev/null +++ b/depends/packages/native_cctools.mk @@ -0,0 +1,60 @@ +package=native_cctools +$(package)_version=807d6fd1be5d2224872e381870c0a75387fe05e6 +$(package)_download_path=https://github.com/theuni/cctools-port/archive +$(package)_file_name=$($(package)_version).tar.gz +$(package)_sha256_hash=a09c9ba4684670a0375e42d9d67e7f12c1f62581a27f28f7c825d6d7032ccc6a +$(package)_build_subdir=cctools +$(package)_clang_version=3.7.1 +$(package)_clang_download_path=http://llvm.org/releases/$($(package)_clang_version) +$(package)_clang_download_file=clang+llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz +$(package)_clang_file_name=clang-llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz +$(package)_clang_sha256_hash=99b28a6b48e793705228a390471991386daa33a9717cd9ca007fcdde69608fd9 +$(package)_extra_sources=$($(package)_clang_file_name) + +define $(package)_fetch_cmds +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_clang_download_path),$($(package)_clang_download_file),$($(package)_clang_file_name),$($(package)_clang_sha256_hash)) +endef + +define $(package)_extract_cmds + mkdir -p toolchain/bin toolchain/lib/clang/3.5/include && \ + tar --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \ + rm -f toolchain/lib/libc++abi.so* && \ + echo "#!/bin/sh" > toolchain/bin/$(host)-dsymutil && \ + echo "exit 0" >> toolchain/bin/$(host)-dsymutil && \ + chmod +x toolchain/bin/$(host)-dsymutil && \ + tar --strip-components=1 -xf $($(package)_source) +endef + +define $(package)_set_vars +$(package)_config_opts=--target=$(host) --disable-lto-support +$(package)_ldflags+=-Wl,-rpath=\\$$$$$$$$\$$$$$$$$ORIGIN/../lib +$(package)_cc=$($(package)_extract_dir)/toolchain/bin/clang +$(package)_cxx=$($(package)_extract_dir)/toolchain/bin/clang++ +endef + +define $(package)_preprocess_cmds + cd $($(package)_build_subdir); ./autogen.sh +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install && \ + cd $($(package)_extract_dir)/toolchain && \ + mkdir -p $($(package)_staging_prefix_dir)/lib/clang/$($(package)_clang_version)/include && \ + mkdir -p $($(package)_staging_prefix_dir)/bin $($(package)_staging_prefix_dir)/include && \ + cp bin/clang $($(package)_staging_prefix_dir)/bin/ &&\ + cp -P bin/clang++ $($(package)_staging_prefix_dir)/bin/ &&\ + cp lib/libLTO.so $($(package)_staging_prefix_dir)/lib/ && \ + cp -rf lib/clang/$($(package)_clang_version)/include/* $($(package)_staging_prefix_dir)/lib/clang/$($(package)_clang_version)/include/ && \ + cp bin/llvm-dsymutil $($(package)_staging_prefix_dir)/bin/$(host)-dsymutil && \ + if `test -d include/c++/`; then cp -rf include/c++/ $($(package)_staging_prefix_dir)/include/; fi && \ + if `test -d lib/c++/`; then cp -rf lib/c++/ $($(package)_staging_prefix_dir)/lib/; fi +endef diff --git a/depends/packages/native_cdrkit.mk b/depends/packages/native_cdrkit.mk new file mode 100644 index 00000000..cf694edb --- /dev/null +++ b/depends/packages/native_cdrkit.mk @@ -0,0 +1,26 @@ +package=native_cdrkit +$(package)_version=1.1.11 +$(package)_download_path=http://distro.ibiblio.org/fatdog/source/600/c +$(package)_file_name=cdrkit-$($(package)_version).tar.bz2 +$(package)_sha256_hash=b50d64c214a65b1a79afe3a964c691931a4233e2ba605d793eb85d0ac3652564 +$(package)_patches=cdrkit-deterministic.patch + +define $(package)_preprocess_cmds + patch -p1 < $($(package)_patch_dir)/cdrkit-deterministic.patch +endef + +define $(package)_config_cmds + cmake -DCMAKE_INSTALL_PREFIX=$(build_prefix) +endef + +define $(package)_build_cmds + $(MAKE) genisoimage +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) -C genisoimage install +endef + +define $(package)_postprocess_cmds + rm bin/isovfy bin/isoinfo bin/isodump bin/isodebug bin/devdump +endef diff --git a/depends/packages/native_ds_store.mk b/depends/packages/native_ds_store.mk new file mode 100644 index 00000000..8e902af1 --- /dev/null +++ b/depends/packages/native_ds_store.mk @@ -0,0 +1,17 @@ +package=native_ds_store +$(package)_version=c80c23706eae +$(package)_download_path=https://bitbucket.org/al45tair/ds_store/get +$(package)_download_file=$($(package)_version).tar.bz2 +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=ce1aa412211610c63d567bbe3e06213006a2d5ba5d76d89399c151b5472cb0da +$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages +$(package)_dependencies=native_biplist + +define $(package)_build_cmds + python setup.py build +endef + +define $(package)_stage_cmds + mkdir -p $($(package)_install_libdir) && \ + python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) +endef diff --git a/depends/packages/native_libdmg-hfsplus.mk b/depends/packages/native_libdmg-hfsplus.mk new file mode 100644 index 00000000..a4ffb604 --- /dev/null +++ b/depends/packages/native_libdmg-hfsplus.mk @@ -0,0 +1,22 @@ +package=native_libdmg-hfsplus +$(package)_version=0.1 +$(package)_download_path=https://github.com/theuni/libdmg-hfsplus/archive +$(package)_file_name=libdmg-hfsplus-v$($(package)_version).tar.gz +$(package)_sha256_hash=6569a02eb31c2827080d7d59001869ea14484c281efab0ae7f2b86af5c3120b3 +$(package)_build_subdir=build + +define $(package)_preprocess_cmds + mkdir build +endef + +define $(package)_config_cmds + cmake -DCMAKE_INSTALL_PREFIX:PATH=$(build_prefix)/bin .. +endef + +define $(package)_build_cmds + $(MAKE) -C dmg +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) -C dmg install +endef diff --git a/depends/packages/native_mac_alias.mk b/depends/packages/native_mac_alias.mk new file mode 100644 index 00000000..d117c1c9 --- /dev/null +++ b/depends/packages/native_mac_alias.mk @@ -0,0 +1,16 @@ +package=native_mac_alias +$(package)_version=1.1.0 +$(package)_download_path=https://bitbucket.org/al45tair/mac_alias/get +$(package)_download_file=v$($(package)_version).tar.bz2 +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=87ad827e66790028361e43fc754f68ed041a9bdb214cca03c853f079b04fb120 +$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages + +define $(package)_build_cmds + python setup.py build +endef + +define $(package)_stage_cmds + mkdir -p $($(package)_install_libdir) && \ + python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) +endef diff --git a/depends/packages/native_protobuf.mk b/depends/packages/native_protobuf.mk new file mode 100644 index 00000000..ce50b366 --- /dev/null +++ b/depends/packages/native_protobuf.mk @@ -0,0 +1,25 @@ +package=native_protobuf +$(package)_version=2.6.1 +$(package)_download_path=https://github.com/google/protobuf/releases/download/v$($(package)_version) +$(package)_file_name=protobuf-$($(package)_version).tar.bz2 +$(package)_sha256_hash=ee445612d544d885ae240ffbcbf9267faa9f593b7b101f21d58beceb92661910 + +define $(package)_set_vars +$(package)_config_opts=--disable-shared +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) -C src protoc +endef + +define $(package)_stage_cmds + $(MAKE) -C src DESTDIR=$($(package)_staging_dir) install-strip +endef + +define $(package)_postprocess_cmds + rm -rf lib include +endef diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk new file mode 100644 index 00000000..5ee9f17a --- /dev/null +++ b/depends/packages/openssl.mk @@ -0,0 +1,78 @@ +package=openssl +$(package)_version=1.0.1k +$(package)_download_path=https://www.openssl.org/source +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=8f9faeaebad088e772f4ef5e38252d472be4d878c6b3a2718c10a4fcebe7a41c + +define $(package)_set_vars +$(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" +$(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl +$(package)_config_opts+=no-camellia +$(package)_config_opts+=no-capieng +$(package)_config_opts+=no-cast +$(package)_config_opts+=no-comp +$(package)_config_opts+=no-dso +$(package)_config_opts+=no-dtls1 +$(package)_config_opts+=no-ec_nistp_64_gcc_128 +$(package)_config_opts+=no-gost +$(package)_config_opts+=no-gmp +$(package)_config_opts+=no-heartbeats +$(package)_config_opts+=no-idea +$(package)_config_opts+=no-jpake +$(package)_config_opts+=no-krb5 +$(package)_config_opts+=no-libunbound +$(package)_config_opts+=no-md2 +$(package)_config_opts+=no-mdc2 +$(package)_config_opts+=no-rc4 +$(package)_config_opts+=no-rc5 +$(package)_config_opts+=no-rdrand +$(package)_config_opts+=no-rfc3779 +$(package)_config_opts+=no-rsax +$(package)_config_opts+=no-sctp +$(package)_config_opts+=no-seed +$(package)_config_opts+=no-sha0 +$(package)_config_opts+=no-shared +$(package)_config_opts+=no-ssl-trace +$(package)_config_opts+=no-ssl2 +$(package)_config_opts+=no-ssl3 +$(package)_config_opts+=no-static_engine +$(package)_config_opts+=no-store +$(package)_config_opts+=no-unit-test +$(package)_config_opts+=no-weak-ssl-ciphers +$(package)_config_opts+=no-whirlpool +$(package)_config_opts+=no-zlib +$(package)_config_opts+=no-zlib-dynamic +$(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags) +$(package)_config_opts_linux=-fPIC -Wa,--noexecstack +$(package)_config_opts_x86_64_linux=linux-x86_64 +$(package)_config_opts_i686_linux=linux-generic32 +$(package)_config_opts_arm_linux=linux-generic32 +$(package)_config_opts_aarch64_linux=linux-generic64 +$(package)_config_opts_mipsel_linux=linux-generic32 +$(package)_config_opts_mips_linux=linux-generic32 +$(package)_config_opts_powerpc_linux=linux-generic32 +$(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc +$(package)_config_opts_x86_64_mingw32=mingw64 +$(package)_config_opts_i686_mingw32=mingw +endef + +define $(package)_preprocess_cmds + sed -i.old "/define DATE/d" util/mkbuildinf.pl && \ + sed -i.old "s|engines apps test|engines|" Makefile.org +endef + +define $(package)_config_cmds + ./Configure $($(package)_config_opts) +endef + +define $(package)_build_cmds + $(MAKE) -j1 build_libs libcrypto.pc libssl.pc openssl.pc +endef + +define $(package)_stage_cmds + $(MAKE) INSTALL_PREFIX=$($(package)_staging_dir) -j1 install_sw +endef + +define $(package)_postprocess_cmds + rm -rf share bin etc +endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk new file mode 100644 index 00000000..f4243bf2 --- /dev/null +++ b/depends/packages/packages.mk @@ -0,0 +1,24 @@ +packages:=boost openssl libevent +darwin_packages:=zeromq +linux_packages:=zeromq +native_packages := native_ccache + +qt_native_packages = native_protobuf +qt_packages = qrencode protobuf + +qt_x86_64_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans +qt_i686_linux_packages:=$(qt_x86_64_linux_packages) + +qt_darwin_packages=qt +qt_mingw32_packages=qt + + +wallet_packages=bdb + +upnp_packages=miniupnpc + +darwin_native_packages = native_biplist native_ds_store native_mac_alias + +ifneq ($(build_os),darwin) +darwin_native_packages += native_cctools native_cdrkit native_libdmg-hfsplus +endif diff --git a/depends/packages/protobuf.mk b/depends/packages/protobuf.mk new file mode 100644 index 00000000..54d3fd92 --- /dev/null +++ b/depends/packages/protobuf.mk @@ -0,0 +1,29 @@ +package=protobuf +$(package)_version=$(native_$(package)_version) +$(package)_download_path=$(native_$(package)_download_path) +$(package)_file_name=$(native_$(package)_file_name) +$(package)_sha256_hash=$(native_$(package)_sha256_hash) +$(package)_dependencies=native_$(package) +$(package)_cxxflags=-std=c++11 + +define $(package)_set_vars + $(package)_config_opts=--disable-shared --with-protoc=$(build_prefix)/bin/protoc + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) -C src libprotobuf.la +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install-libLTLIBRARIES install-nobase_includeHEADERS &&\ + $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA +endef + +define $(package)_postprocess_cmds + rm lib/libprotoc.a +endef diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk new file mode 100644 index 00000000..7b212471 --- /dev/null +++ b/depends/packages/qrencode.mk @@ -0,0 +1,22 @@ +package=qrencode +$(package)_version=3.4.4 +$(package)_download_path=https://fukuchi.org/works/qrencode/ +$(package)_file_name=qrencode-$(qrencode_version).tar.bz2 +$(package)_sha256_hash=efe5188b1ddbcbf98763b819b146be6a90481aac30cfc8d858ab78a19cde1fa5 + +define $(package)_set_vars +$(package)_config_opts=--disable-shared -without-tools --disable-sdltest +$(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk new file mode 100644 index 00000000..1f2bc140 --- /dev/null +++ b/depends/packages/qt.mk @@ -0,0 +1,182 @@ +PACKAGE=qt +$(package)_version=5.6.1 +$(package)_download_path=http://download.qt.io/official_releases/qt/5.6/$($(package)_version)/submodules +$(package)_suffix=opensource-src-$($(package)_version).tar.gz +$(package)_file_name=qtbase-$($(package)_suffix) +$(package)_sha256_hash=0ac67cf8d66d52b995f96c31c4b48117a1afb3db99eaa93e20ccd8f7f55f7fde +$(package)_dependencies=openssl +$(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext +$(package)_build_subdir=qtbase +$(package)_qt_libs=corelib network widgets gui plugins testlib +$(package)_patches=mac-qmake.conf mingw-uuidof.patch pidlist_absolute.patch fix-xcb-include-order.patch fix_qt_pkgconfig.patch + +$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) +$(package)_qttranslations_sha256_hash=dcc1534d247babca1840cb6d0a000671801a341ea352d0535474f86adadaf028 + + +$(package)_qttools_file_name=qttools-$($(package)_suffix) +$(package)_qttools_sha256_hash=e0f845de28c31230dfa428f0190ccb3b91d1fc02481b1f064698ae4ef8376aa1 + +$(package)_extra_sources = $($(package)_qttranslations_file_name) +$(package)_extra_sources += $($(package)_qttools_file_name) + +define $(package)_set_vars +$(package)_config_opts_release = -release +$(package)_config_opts_debug = -debug +$(package)_config_opts += -bindir $(build_prefix)/bin +$(package)_config_opts += -c++11 +$(package)_config_opts += -confirm-license +$(package)_config_opts += -dbus-runtime +$(package)_config_opts += -hostprefix $(build_prefix) +$(package)_config_opts += -no-alsa +$(package)_config_opts += -no-audio-backend +$(package)_config_opts += -no-cups +$(package)_config_opts += -no-egl +$(package)_config_opts += -no-eglfs +$(package)_config_opts += -no-feature-style-windowsmobile +$(package)_config_opts += -no-feature-style-windowsce +$(package)_config_opts += -no-freetype +$(package)_config_opts += -no-gif +$(package)_config_opts += -no-glib +$(package)_config_opts += -no-gstreamer +$(package)_config_opts += -no-icu +$(package)_config_opts += -no-iconv +$(package)_config_opts += -no-kms +$(package)_config_opts += -no-linuxfb +$(package)_config_opts += -no-libudev +$(package)_config_opts += -no-mitshm +$(package)_config_opts += -no-mtdev +$(package)_config_opts += -no-nis +$(package)_config_opts += -no-pulseaudio +$(package)_config_opts += -no-openvg +$(package)_config_opts += -no-reduce-relocations +$(package)_config_opts += -no-qml-debug +$(package)_config_opts += -no-sql-db2 +$(package)_config_opts += -no-sql-ibase +$(package)_config_opts += -no-sql-oci +$(package)_config_opts += -no-sql-tds +$(package)_config_opts += -no-sql-mysql +$(package)_config_opts += -no-sql-odbc +$(package)_config_opts += -no-sql-psql +$(package)_config_opts += -no-sql-sqlite +$(package)_config_opts += -no-sql-sqlite2 +$(package)_config_opts += -no-use-gold-linker +$(package)_config_opts += -no-xinput2 +$(package)_config_opts += -no-xrender +$(package)_config_opts += -nomake examples +$(package)_config_opts += -nomake tests +$(package)_config_opts += -opensource +$(package)_config_opts += -openssl-linked +$(package)_config_opts += -optimized-qmake +$(package)_config_opts += -pch +$(package)_config_opts += -pkg-config +$(package)_config_opts += -prefix $(host_prefix) +$(package)_config_opts += -qt-libpng +$(package)_config_opts += -qt-libjpeg +$(package)_config_opts += -qt-pcre +$(package)_config_opts += -qt-zlib +$(package)_config_opts += -reduce-exports +$(package)_config_opts += -static +$(package)_config_opts += -silent +$(package)_config_opts += -v + +ifneq ($(build_os),darwin) +$(package)_config_opts_darwin = -xplatform macx-clang-linux +$(package)_config_opts_darwin += -device-option MAC_SDK_PATH=$(OSX_SDK) +$(package)_config_opts_darwin += -device-option MAC_SDK_VERSION=$(OSX_SDK_VERSION) +$(package)_config_opts_darwin += -device-option CROSS_COMPILE="$(host)-" +$(package)_config_opts_darwin += -device-option MAC_MIN_VERSION=$(OSX_MIN_VERSION) +$(package)_config_opts_darwin += -device-option MAC_TARGET=$(host) +$(package)_config_opts_darwin += -device-option MAC_LD64_VERSION=$(LD64_VERSION) +endif + +$(package)_config_opts_linux = -qt-xkbcommon +$(package)_config_opts_linux += -qt-xcb +$(package)_config_opts_linux += -system-freetype +$(package)_config_opts_linux += -no-sm +$(package)_config_opts_linux += -fontconfig +$(package)_config_opts_linux += -no-opengl +$(package)_config_opts_arm_linux = -platform linux-g++ -xplatform $(host) +$(package)_config_opts_i686_linux = -xplatform linux-g++-32 +$(package)_config_opts_mingw32 = -no-opengl -xplatform win32-g++ -device-option CROSS_COMPILE="$(host)-" +$(package)_build_env = QT_RCC_TEST=1 +endef + +define $(package)_fetch_cmds +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_qttranslations_file_name),$($(package)_qttranslations_file_name),$($(package)_qttranslations_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_qttools_file_name),$($(package)_qttools_file_name),$($(package)_qttools_sha256_hash)) +endef + +define $(package)_extract_cmds + mkdir -p $($(package)_extract_dir) && \ + echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_qttranslations_sha256_hash) $($(package)_source_dir)/$($(package)_qttranslations_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_qttools_sha256_hash) $($(package)_source_dir)/$($(package)_qttools_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + mkdir qtbase && \ + tar --strip-components=1 -xf $($(package)_source) -C qtbase && \ + mkdir qttranslations && \ + tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttranslations_file_name) -C qttranslations && \ + mkdir qttools && \ + tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools +endef + + +define $(package)_preprocess_cmds + sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ + sed -i.old "s/src_plugins.depends = src_sql src_xml src_network/src_plugins.depends = src_xml src_network/" qtbase/src/src.pro && \ + sed -i.old "s|X11/extensions/XIproto.h|X11/X.h|" qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp && \ + sed -i.old 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' qtbase/configure && \ + sed -i.old 's/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0)/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft)/' qtbase/src/plugins/platforms/cocoa/qcocoacursor.mm && \ + mkdir -p qtbase/mkspecs/macx-clang-linux &&\ + cp -f qtbase/mkspecs/macx-clang/Info.plist.lib qtbase/mkspecs/macx-clang-linux/ &&\ + cp -f qtbase/mkspecs/macx-clang/Info.plist.app qtbase/mkspecs/macx-clang-linux/ &&\ + cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\ + cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \ + patch -p1 < $($(package)_patch_dir)/mingw-uuidof.patch && \ + patch -p1 < $($(package)_patch_dir)/pidlist_absolute.patch && \ + patch -p1 < $($(package)_patch_dir)/fix-xcb-include-order.patch && \ + patch -p1 < $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \ + echo "QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ + echo "QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ + echo "QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ + sed -i.old "s|QMAKE_CFLAGS = |QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ + sed -i.old "s|QMAKE_LFLAGS = |QMAKE_LFLAGS = $($(package)_ldflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ + sed -i.old "s|QMAKE_CXXFLAGS = |QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf +endef + +define $(package)_config_cmds + export PKG_CONFIG_SYSROOT_DIR=/ && \ + export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \ + export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \ + ./configure $($(package)_config_opts) && \ + $(MAKE) sub-src-clean && \ + cd ../qttranslations && ../qtbase/bin/qmake qttranslations.pro -o Makefile && \ + cd translations && ../../qtbase/bin/qmake translations.pro -o Makefile && cd ../.. &&\ + cd qttools/src/linguist/lrelease/ && ../../../../qtbase/bin/qmake lrelease.pro -o Makefile +endef + +define $(package)_build_cmds + $(MAKE) -C src $(addprefix sub-,$($(package)_qt_libs)) && \ + $(MAKE) -C ../qttools/src/linguist/lrelease && \ + $(MAKE) -C ../qttranslations +endef + +define $(package)_stage_cmds + $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_qt_libs))) && cd .. &&\ + $(MAKE) -C qttools/src/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install_target && \ + $(MAKE) -C qttranslations INSTALL_ROOT=$($(package)_staging_dir) install_subtargets && \ + if `test -f qtbase/src/plugins/platforms/xcb/xcb-static/libxcb-static.a`; then \ + cp qtbase/src/plugins/platforms/xcb/xcb-static/libxcb-static.a $($(package)_staging_prefix_dir)/lib; \ + fi +endef + +define $(package)_postprocess_cmds + rm -rf native/mkspecs/ native/lib/ lib/cmake/ && \ + rm -f lib/lib*.la lib/*.prl plugins/*/*.prl && \ + if `test -f bin/uic`; then cp bin/uic native/bin/; fi && \ + if `test -f bin/lrelease`; then cp bin/lrelease native/bin/; fi && \ + if `test -f bin/qdbuscpp2xml`; then cp bin/qdbuscpp2xml native/bin/; fi && \ + if `test -f bin/qdbusxml2cpp`; then cp bin/qdbusxml2cpp native/bin/; fi +endef diff --git a/depends/packages/qt46.mk b/depends/packages/qt46.mk new file mode 100644 index 00000000..8fb30a5c --- /dev/null +++ b/depends/packages/qt46.mk @@ -0,0 +1,66 @@ +PACKAGE=qt46 +$(package)_version=4.6.4 +$(package)_download_path=http://download.qt-project.org/archive/qt/4.6/ +$(package)_file_name=qt-everywhere-opensource-src-$($(package)_version).tar.gz +$(package)_sha256_hash=9ad4d46c721b53a429ed5a2eecfd3c239a9ab566562f183f99d3125f1a234250 +$(package)_dependencies=openssl freetype dbus libX11 xproto libXext libICE libSM +$(package)_patches=stlfix.patch + +define $(package)_set_vars +$(package)_config_opts = -prefix $(host_prefix) -headerdir $(host_prefix)/include/qt4 -bindir $(build_prefix)/bin +$(package)_config_opts += -release -no-separate-debug-info -opensource -confirm-license +$(package)_config_opts += -stl -qt-zlib + +$(package)_config_opts += -nomake examples -nomake tests -nomake tools -nomake translations -nomake demos -nomake docs +$(package)_config_opts += -no-audio-backend -no-glib -no-nis -no-cups -no-iconv -no-gif -no-pch +$(package)_config_opts += -no-xkb -no-xrender -no-xrandr -no-xfixes -no-xcursor -no-xinerama -no-xsync -no-xinput -no-mitshm -no-xshape +$(package)_config_opts += -no-libtiff -no-fontconfig -openssl-linked +$(package)_config_opts += -no-sql-db2 -no-sql-ibase -no-sql-oci -no-sql-tds -no-sql-mysql +$(package)_config_opts += -no-sql-odbc -no-sql-psql -no-sql-sqlite -no-sql-sqlite2 +$(package)_config_opts += -no-xmlpatterns -no-multimedia -no-phonon -no-scripttools -no-declarative +$(package)_config_opts += -no-phonon-backend -no-webkit -no-javascript-jit -no-script +$(package)_config_opts += -no-svg -no-libjpeg -no-libtiff -no-libpng -no-libmng -no-qt3support -no-opengl + +$(package)_config_opts_x86_64_linux += -platform linux-g++-64 +$(package)_config_opts_i686_linux = -platform linux-g++-32 +$(package)_build_env = QT_RCC_TEST=1 +endef + +define $(package)_preprocess_cmds + sed -i.old "s|/include /usr/include||" config.tests/unix/freetype/freetype.pri && \ + sed -i.old "s|src_plugins.depends = src_gui src_sql src_svg|src_plugins.depends = src_gui src_sql|" src/src.pro && \ + sed -i.old "s|\.lower(|\.toLower(|g" src/network/ssl/qsslsocket_openssl.cpp && \ + sed -i.old "s|Key_BackSpace|Key_Backspace|" src/gui/itemviews/qabstractitemview.cpp && \ + sed -i.old "s|/usr/X11R6/lib64|$(host_prefix)/lib|" mkspecs/*/*.conf && \ + sed -i.old "s|/usr/X11R6/lib|$(host_prefix)/lib|" mkspecs/*/*.conf && \ + sed -i.old "s|/usr/X11R6/include|$(host_prefix)/include|" mkspecs/*/*.conf && \ + sed -i.old "s|QMAKE_LFLAGS_SHLIB\t+= -shared|QMAKE_LFLAGS_SHLIB\t+= -shared -Wl,--exclude-libs,ALL|" mkspecs/common/g++.conf && \ + sed -i.old "/SSLv2_client_method/d" src/network/ssl/qsslsocket_openssl.cpp src/network/ssl/qsslsocket_openssl_symbols.cpp && \ + sed -i.old "/SSLv2_server_method/d" src/network/ssl/qsslsocket_openssl.cpp src/network/ssl/qsslsocket_openssl_symbols.cpp && \ + patch -p1 < $($(package)_patch_dir)/stlfix.patch +endef + +define $(package)_config_cmds + export PKG_CONFIG_SYSROOT_DIR=/ && \ + export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \ + export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \ + export CPATH=$(host_prefix)/include && \ + OPENSSL_LIBS='-L$(host_prefix)/lib -lssl -lcrypto' ./configure $($(package)_config_opts) && \ + cd tools/linguist/lrelease; ../../../bin/qmake -o Makefile lrelease.pro +endef + +define $(package)_build_cmds + export CPATH=$(host_prefix)/include && \ + $(MAKE) -C src && \ + $(MAKE) -C tools/linguist/lrelease +endef + +define $(package)_stage_cmds + $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) install && \ + $(MAKE) -C tools/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm -rf mkspecs/ lib/cmake/ lib/*.prl lib/*.la && \ + find native/bin -type f -exec mv {} {}-qt4 \; +endef diff --git a/depends/packages/xcb_proto.mk b/depends/packages/xcb_proto.mk new file mode 100644 index 00000000..0c7c958d --- /dev/null +++ b/depends/packages/xcb_proto.mk @@ -0,0 +1,27 @@ +package=xcb_proto +$(package)_version=1.10 +$(package)_download_path=http://xcb.freedesktop.org/dist +$(package)_file_name=xcb-proto-$($(package)_version).tar.bz2 +$(package)_sha256_hash=7ef40ddd855b750bc597d2a435da21e55e502a0fefa85b274f2c922800baaf05 + +define $(package)_set_vars + $(package)_config_opts=--disable-shared + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + find -name "*.pyc" -delete && \ + find -name "*.pyo" -delete +endef diff --git a/depends/packages/xextproto.mk b/depends/packages/xextproto.mk new file mode 100644 index 00000000..98a11eb4 --- /dev/null +++ b/depends/packages/xextproto.mk @@ -0,0 +1,21 @@ +package=xextproto +$(package)_version=7.3.0 +$(package)_download_path=http://xorg.freedesktop.org/releases/individual/proto +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=f3f4b23ac8db9c3a9e0d8edb591713f3d70ef9c3b175970dd8823dfc92aa5bb0 + +define $(package)_set_vars +$(package)_config_opts=--disable-shared +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/xproto.mk b/depends/packages/xproto.mk new file mode 100644 index 00000000..50a90b26 --- /dev/null +++ b/depends/packages/xproto.mk @@ -0,0 +1,21 @@ +package=xproto +$(package)_version=7.0.26 +$(package)_download_path=http://xorg.freedesktop.org/releases/individual/proto +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=636162c1759805a5a0114a369dffdeccb8af8c859ef6e1445f26a4e6e046514f + +define $(package)_set_vars +$(package)_config_opts=--disable-shared +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/xtrans.mk b/depends/packages/xtrans.mk new file mode 100644 index 00000000..99eefa6d --- /dev/null +++ b/depends/packages/xtrans.mk @@ -0,0 +1,22 @@ +package=xtrans +$(package)_version=1.3.4 +$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=054d4ee3efd52508c753e9f7bc655ef185a29bd2850dd9e2fc2ccc33544f583a +$(package)_dependencies= + +define $(package)_set_vars +$(package)_config_opts_linux=--with-pic --disable-static +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk new file mode 100644 index 00000000..b3f18db0 --- /dev/null +++ b/depends/packages/zeromq.mk @@ -0,0 +1,27 @@ +package=zeromq +$(package)_version=4.0.7 +$(package)_download_path=http://download.zeromq.org +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=e00b2967e074990d0538361cc79084a0a92892df2c6e7585da34e4c61ee47b03 + +define $(package)_set_vars + $(package)_config_opts=--without-documentation --disable-shared + $(package)_config_opts_linux=--with-pic + $(package)_cxxflags=-std=c++11 +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) -C src +endef + +define $(package)_stage_cmds + $(MAKE) -C src DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm -rf bin share +endef diff --git a/depends/patches/boost/darwin_boost_atomic-1.patch b/depends/patches/boost/darwin_boost_atomic-1.patch new file mode 100644 index 00000000..97f59cb7 --- /dev/null +++ b/depends/patches/boost/darwin_boost_atomic-1.patch @@ -0,0 +1,35 @@ +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 + + 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 + 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 new file mode 100644 index 00000000..ca507652 --- /dev/null +++ b/depends/patches/boost/darwin_boost_atomic-2.patch @@ -0,0 +1,55 @@ +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 + + 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 + + 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 + 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 + 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 new file mode 100644 index 00000000..04514c59 --- /dev/null +++ b/depends/patches/boost/gcc_5_no_cxx11.patch @@ -0,0 +1,37 @@ +From eec808554936ae068b23df07ab54d4dc6302a695 Mon Sep 17 00:00:00 2001 +From: jzmaddock +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/depends/patches/libevent/reuseaddr.patch b/depends/patches/libevent/reuseaddr.patch new file mode 100644 index 00000000..58695c11 --- /dev/null +++ b/depends/patches/libevent/reuseaddr.patch @@ -0,0 +1,21 @@ +--- old/evutil.c 2015-08-28 19:26:23.488765923 -0400 ++++ new/evutil.c 2015-08-28 19:27:41.392767019 -0400 +@@ -321,15 +321,16 @@ + int + evutil_make_listen_socket_reuseable(evutil_socket_t sock) + { +-#ifndef WIN32 + int one = 1; ++#ifndef WIN32 + /* REUSEADDR on Unix means, "don't hang on to this address after the + * listener is closed." On Windows, though, it means "don't keep other + * processes from binding to this address while we're using it. */ + return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one, + (ev_socklen_t)sizeof(one)); + #else +- return 0; ++ return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*) &one, ++ (ev_socklen_t)sizeof(one)); + #endif + } + diff --git a/depends/patches/native_cdrkit/cdrkit-deterministic.patch b/depends/patches/native_cdrkit/cdrkit-deterministic.patch new file mode 100644 index 00000000..8ab0993d --- /dev/null +++ b/depends/patches/native_cdrkit/cdrkit-deterministic.patch @@ -0,0 +1,86 @@ +--- cdrkit-1.1.11.old/genisoimage/tree.c 2008-10-21 19:57:47.000000000 -0400 ++++ cdrkit-1.1.11/genisoimage/tree.c 2013-12-06 00:23:18.489622668 -0500 +@@ -1139,8 +1139,9 @@ + scan_directory_tree(struct directory *this_dir, char *path, + struct directory_entry *de) + { +- DIR *current_dir; ++ int current_file; + char whole_path[PATH_MAX]; ++ struct dirent **d_list; + struct dirent *d_entry; + struct directory *parent; + int dflag; +@@ -1164,7 +1165,8 @@ + this_dir->dir_flags |= DIR_WAS_SCANNED; + + errno = 0; /* Paranoia */ +- current_dir = opendir(path); ++ //current_dir = opendir(path); ++ current_file = scandir(path, &d_list, NULL, alphasort); + d_entry = NULL; + + /* +@@ -1173,12 +1175,12 @@ + */ + old_path = path; + +- if (current_dir) { ++ if (current_file >= 0) { + errno = 0; +- d_entry = readdir(current_dir); ++ d_entry = d_list[0]; + } + +- if (!current_dir || !d_entry) { ++ if (current_file < 0 || !d_entry) { + int ret = 1; + + #ifdef USE_LIBSCHILY +@@ -1191,8 +1193,8 @@ + de->isorec.flags[0] &= ~ISO_DIRECTORY; + ret = 0; + } +- if (current_dir) +- closedir(current_dir); ++ if(d_list) ++ free(d_list); + return (ret); + } + #ifdef ABORT_DEEP_ISO_ONLY +@@ -1208,7 +1210,7 @@ + errmsgno(EX_BAD, "use Rock Ridge extensions via -R or -r,\n"); + errmsgno(EX_BAD, "or allow deep ISO9660 directory nesting via -D.\n"); + } +- closedir(current_dir); ++ free(d_list); + return (1); + } + #endif +@@ -1250,13 +1252,13 @@ + * The first time through, skip this, since we already asked + * for the first entry when we opened the directory. + */ +- if (dflag) +- d_entry = readdir(current_dir); ++ if (dflag && current_file >= 0) ++ d_entry = d_list[current_file]; + dflag++; + +- if (!d_entry) ++ if (current_file < 0) + break; +- ++ current_file--; + /* OK, got a valid entry */ + + /* If we do not want all files, then pitch the backups. */ +@@ -1348,7 +1350,7 @@ + insert_file_entry(this_dir, whole_path, d_entry->d_name); + #endif /* APPLE_HYB */ + } +- closedir(current_dir); ++ free(d_list); + + #ifdef APPLE_HYB + /* diff --git a/depends/patches/qt/fix-xcb-include-order.patch b/depends/patches/qt/fix-xcb-include-order.patch new file mode 100644 index 00000000..c7dbebed --- /dev/null +++ b/depends/patches/qt/fix-xcb-include-order.patch @@ -0,0 +1,49 @@ +--- old/qtbase/src/plugins/platforms/xcb/xcb_qpa_lib.pro 2015-03-17 02:06:42.705930685 +0000 ++++ new/qtbase/src/plugins/platforms/xcb/xcb_qpa_lib.pro 2015-03-17 02:08:41.281926351 +0000 +@@ -74,8 +74,6 @@ + + DEFINES += $$QMAKE_DEFINES_XCB + LIBS += $$QMAKE_LIBS_XCB +-QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XCB +-QMAKE_CFLAGS += $$QMAKE_CFLAGS_XCB + + CONFIG += qpa/genericunixfontdatabase + +@@ -87,7 +85,8 @@ + contains(QT_CONFIG, xcb-qt) { + DEFINES += XCB_USE_RENDER + XCB_DIR = ../../../3rdparty/xcb +- INCLUDEPATH += $$XCB_DIR/include $$XCB_DIR/sysinclude ++ QMAKE_CFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/sysinclude $$QMAKE_CFLAGS_XCB ++ QMAKE_CXXFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/sysinclude $$QMAKE_CFLAGS_XCB + LIBS += -lxcb -L$$OUT_PWD/xcb-static -lxcb-static + } else { + LIBS += -lxcb -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr -lxcb-shape -lxcb-keysyms -lxcb-xinerama +--- old/qtbase/src/plugins/platforms/xcb/xcb-static/xcb-static.pro 2015-03-17 02:07:04.641929383 +0000 ++++ new/qtbase/src/plugins/platforms/xcb/xcb-static/xcb-static.pro 2015-03-17 02:10:15.485922059 +0000 +@@ -9,7 +9,8 @@ + + XCB_DIR = ../../../../3rdparty/xcb + +-INCLUDEPATH += $$XCB_DIR/include $$XCB_DIR/include/xcb $$XCB_DIR/sysinclude ++QMAKE_CFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/include/xcb -I$$XCB_DIR/sysinclude ++QMAKE_CXXFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/include/xcb -I$$XCB_DIR/sysinclude + + QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XCB + QMAKE_CFLAGS += $$QMAKE_CFLAGS_XCB +--- old/qtbase/src/plugins/platforms/xcb/xcb-plugin.pro 2015-07-24 16:02:59.530038830 -0400 ++++ new/qtbase/src/plugins/platforms/xcb/xcb-plugin.pro 2015-07-24 16:01:22.106037459 -0400 +@@ -6,6 +6,13 @@ + qxcbmain.cpp + OTHER_FILES += xcb.json README + ++contains(QT_CONFIG, xcb-qt) { ++ DEFINES += XCB_USE_RENDER ++ XCB_DIR = ../../../3rdparty/xcb ++ QMAKE_CFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/sysinclude $$QMAKE_CFLAGS_XCB ++ QMAKE_CXXFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/sysinclude $$QMAKE_CFLAGS_XCB ++} ++ + PLUGIN_TYPE = platforms + PLUGIN_CLASS_NAME = QXcbIntegrationPlugin + !equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - diff --git a/depends/patches/qt/fix_qt_pkgconfig.patch b/depends/patches/qt/fix_qt_pkgconfig.patch new file mode 100644 index 00000000..3772db4f --- /dev/null +++ b/depends/patches/qt/fix_qt_pkgconfig.patch @@ -0,0 +1,11 @@ +--- old/qtbase/mkspecs/features/qt_module.prf 2016-03-17 02:06:42.705930685 +0000 ++++ new/qtbase/mkspecs/features/qt_module.prf 2016-03-17 02:06:42.705930685 +0000 +@@ -244,7 +244,7 @@ + load(qt_targets) + + # this builds on top of qt_common +-!internal_module:!lib_bundle:if(unix|mingw) { ++unix|mingw { + CONFIG += create_pc + QMAKE_PKGCONFIG_DESTDIR = pkgconfig + host_build: \ diff --git a/depends/patches/qt/mac-qmake.conf b/depends/patches/qt/mac-qmake.conf new file mode 100644 index 00000000..a6d0070c --- /dev/null +++ b/depends/patches/qt/mac-qmake.conf @@ -0,0 +1,26 @@ +MAKEFILE_GENERATOR = UNIX +CONFIG += app_bundle incremental global_init_link_order lib_version_first plugin_no_soname absolute_library_soname +DEFINES += QT_NO_PRINTER QT_NO_PRINTDIALOG +QMAKE_INCREMENTAL_STYLE = sublib +include(../common/macx.conf) +include(../common/gcc-base-mac.conf) +include(../common/clang.conf) +include(../common/clang-mac.conf) +QMAKE_MAC_SDK_PATH=$${MAC_SDK_PATH} +QMAKE_XCODE_VERSION=4.3 +QMAKE_XCODE_DEVELOPER_PATH=/Developer +QMAKE_MACOSX_DEPLOYMENT_TARGET = $${MAC_MIN_VERSION} +QMAKE_MAC_SDK=macosx +QMAKE_MAC_SDK.macosx.path = $${MAC_SDK_PATH} +QMAKE_MAC_SDK.macosx.platform_name = macosx +QMAKE_MAC_SDK.macosx.version = $${MAC_SDK_VERSION} +QMAKE_MAC_SDK.macosx.platform_path = /phony +QMAKE_CFLAGS += -target $${MAC_TARGET} +QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_CFLAGS +QMAKE_CXXFLAGS += $$QMAKE_CFLAGS +QMAKE_LFLAGS += -target $${MAC_TARGET} -mlinker-version=$${MAC_LD64_VERSION} +QMAKE_AR = $${CROSS_COMPILE}ar cq +QMAKE_RANLIB=$${CROSS_COMPILE}ranlib +QMAKE_LIBTOOL=$${CROSS_COMPILE}libtool +QMAKE_INSTALL_NAME_TOOL=$${CROSS_COMPILE}install_name_tool +load(qt_config) diff --git a/depends/patches/qt/mingw-uuidof.patch b/depends/patches/qt/mingw-uuidof.patch new file mode 100644 index 00000000..975366e6 --- /dev/null +++ b/depends/patches/qt/mingw-uuidof.patch @@ -0,0 +1,44 @@ +--- old/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp 2015-06-20 17:40:20.956781548 -0400 ++++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp 2015-06-20 17:29:32.052772416 -0400 +@@ -69,7 +69,7 @@ + #include + #include + #include +-#ifndef Q_OS_WINCE ++#if !defined(Q_OS_WINCE) && (!defined(USE___UUIDOF) || (defined(USE___UUIDOF) && USE___UUIDOF == 1)) + # include + #endif + +@@ -762,7 +762,7 @@ + HWND_MESSAGE, NULL, (HINSTANCE)GetModuleHandle(0), NULL); + } + +-#ifndef Q_OS_WINCE ++#if !defined(Q_OS_WINCE) && (!defined(USE___UUIDOF) || (defined(USE___UUIDOF) && USE___UUIDOF == 1)) + // Re-engineered from the inline function _com_error::ErrorMessage(). + // We cannot use it directly since it uses swprintf_s(), which is not + // present in the MSVCRT.DLL found on Windows XP (QTBUG-35617). +@@ -781,7 +781,7 @@ + return QStringLiteral("IDispatch error #") + QString::number(wCode); + return QStringLiteral("Unknown error 0x0") + QString::number(comError.Error(), 16); + } +-#endif // !Q_OS_WINCE ++#endif // !defined(Q_OS_WINCE) && (!defined(USE___UUIDOF) || (defined(USE___UUIDOF) && USE___UUIDOF == 1)) + + /*! + \brief Common COM error strings. +@@ -846,12 +846,12 @@ + default: + break; + } +-#ifndef Q_OS_WINCE ++#if !defined(Q_OS_WINCE) && (!defined(USE___UUIDOF) || (defined(USE___UUIDOF) && USE___UUIDOF == 1)) + _com_error error(hr); + result += QByteArrayLiteral(" ("); + result += errorMessageFromComError(error); + result += ')'; +-#endif // !Q_OS_WINCE ++#endif // !defined(Q_OS_WINCE) && (!defined(USE___UUIDOF) || (defined(USE___UUIDOF) && USE___UUIDOF == 1)) + return result; + } + diff --git a/depends/patches/qt/pidlist_absolute.patch b/depends/patches/qt/pidlist_absolute.patch new file mode 100644 index 00000000..0b49c050 --- /dev/null +++ b/depends/patches/qt/pidlist_absolute.patch @@ -0,0 +1,37 @@ +diff -dur old/qtbase/src/plugins/platforms/windows/qwindowscontext.h new/qtbase/src/plugins/platforms/windows/qwindowscontext.h +--- old/qtbase/src/plugins/platforms/windows/qwindowscontext.h 2015-06-29 22:04:40.000000000 +0200 ++++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.h 2015-11-01 12:55:59.751234846 +0100 +@@ -124,10 +124,18 @@ + inline void init(); + + typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **); ++#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) ++ typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, ITEMIDLIST **); ++#else + typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, PIDLIST_ABSOLUTE *); ++#endif + typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *); + typedef HRESULT (WINAPI *SHGetImageList)(int, REFIID , void **); ++#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) ++ typedef HRESULT (WINAPI *SHCreateItemFromIDList)(const ITEMIDLIST *, REFIID, void **); ++#else + typedef HRESULT (WINAPI *SHCreateItemFromIDList)(PCIDLIST_ABSOLUTE, REFIID, void **); ++#endif + + SHCreateItemFromParsingName sHCreateItemFromParsingName; + SHGetKnownFolderIDList sHGetKnownFolderIDList; +diff -dur old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +--- old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp 2015-06-29 22:04:40.000000000 +0200 ++++ new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp 2015-11-01 13:41:09.503149772 +0100 +@@ -1008,7 +1008,11 @@ + qWarning() << __FUNCTION__ << ": Invalid CLSID: " << url.path(); + return Q_NULLPTR; + } ++#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) ++ ITEMIDLIST *idList; ++#else + PIDLIST_ABSOLUTE idList; ++#endif + HRESULT hr = QWindowsContext::shell32dll.sHGetKnownFolderIDList(uuid, 0, 0, &idList); + if (FAILED(hr)) { + qErrnoWarning("%s: SHGetKnownFolderIDList(%s)) failed", __FUNCTION__, qPrintable(url.toString())); diff --git a/depends/patches/qt46/stlfix.patch b/depends/patches/qt46/stlfix.patch new file mode 100644 index 00000000..f8f6fb04 --- /dev/null +++ b/depends/patches/qt46/stlfix.patch @@ -0,0 +1,10 @@ +--- old/config.tests/unix/stl/stltest.cpp 2011-06-23 03:45:23.000000000 -0400 ++++ new/config.tests/unix/stl/stltest.cpp 2014-08-28 00:54:04.154837604 -0400 +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + + // something mean to see if the compiler and C++ standard lib are good enough + template diff --git a/doc/rpc.md b/doc/rpc.md new file mode 100644 index 00000000..34ece3b6 --- /dev/null +++ b/doc/rpc.md @@ -0,0 +1,846 @@ +E-Currency Coin RPC Commands +===================================== + +abandontransaction +------------------ +Mark in-wallet transaction as abandoned + +This will mark this transaction and all its in-wallet descendants as abandoned which will allow for their inputs to be respent. It can be used to replace "stuck" or evicted transactions. It only works on transactions which are not included in a block and are not currently in the mempool. It has no effect on transactions which are already conflicted or abandoned. + +Syntax: +abandontransaction "txid" + +Arguments: +1. "txid" (string, required) The transaction id + +Result: +none + +Examples: +1. Abandon a transaction with txid 1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d + abandontransaction "1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d" + + +addmultisigaddress +------------------ +Add a nrequired-to-sign multisignature address to the wallet. + +Each key is a Bitcoin address or hex-encoded public key. If 'account' is specified (DEPRECATED), assign address to that account. + +Syntax: +addmultisigaddress nrequired ["key",...] "account" + +Arguments: +1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses. +2. keysobject (string, required) A json array of bitcoin addresses or hex-encoded public keys + [ + "address" (string) bitcoin address or hex-encoded public key + ..., + ] +3. account (string, OPTIONAL) DEPRECATED. An account to assign the addresses to. + +Result: +bitcoinaddress (string) A bitcoin address associated with the keys. + +Examples: +1. Add a multisig address from 2 addresses + addmultisigaddress 2 "["16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5", "171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV"]" + + +addnode +------- +Attempts add or remove a node from the addnode list. Or try a connection to a node once. + +Syntax: +addnode "node" "add|remove|onetry" + +Arguments: +1. "node" (string, required) The node (see getpeerinfo for nodes) +2. "command" (string, required) 'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once + +Result: +none + +Examples: +1. Add a node to the node list + addnode "192.168.0.6:8333" "add" +2. Remove a node from the node list + addnode "192.168.0.6:8333" "remove" +3. Try a connection to a node once + addnode "192.168.0.6:8333" "onetry" + + +backupwallet +------------ +Safely copies wallet.dat to destination, which can be a directory or a path with filename. + +Syntax: +backupwallet "destination" + +Arguments: +1. "destination" (string) The destination directory or file + +Result: +no output, but a file with the name given should appear in the desired directory + +Examples: +1. Backup wallet to the same folder with the name backup.dat + backupwallet "backup.dat" + + +clearbanned +----------- +Clear all banned IPs. + +Syntax: +clearbanned + +Arguments: +none + +Result: +none + +Examples: +1. Delete the list of nodes that are banned from connecting to our node + clearbanned + + +createmultisig +-------------- +Creates a multi-signature address with n signature of m keys required. It returns a json object with the address and redeemScript. + +Syntax: +createmultisig nrequired ["key",...] + +Arguments: +1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses. +2. "keys" (string, required) A json array of keys which are E-CurrencyCoin addresses or hex-encoded public keys + [ + "key" (string) E-CurrencyCoin address or hex-encoded public key + ,... + ] + +Result: +JSON object in the following format +{ + "address:"multisigaddress", (string) The value of the new multisig address. + "redeemScript":"script" (string) The std::string value of the hex-encoded redemption script. +} + +Examples: +1. Create a multisig address from 2 addresses + createmultisig 2 ["16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5","171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV"] + + + +decodescript +------------ +Decode a hex-encoded script. + +Syntax: +decodescript "hex" + +Arguments: +1. "hex" (string) the hex encoded script + +Result: +JSON object in the following format +{ + "asm":"asm", (string) Script public key + "hex":"hex", (string) hex encoded public key + "type":"type", (string) The output type + "reqSigs": n, (numeric) The required signatures + "addresses": [ (json array of string) + "address" (string) E-CurrencyCoin address + ,... + ], + "p2sh", + "address" (string) script address +} + +nExamples: +1. decode the script hexstring + decodescript "hexstring" + + +disconnectnode +-------------- +Immediately disconnects from the specified node. + +Syntax: +disconnectnode "node" + +Arguments: +1. "node" (string, required) The node (see getpeerinfo for nodes) + +Result: +none + +Examples: +1. Disconnect from the node 192.168.0.6 + disconnectnode "192.168.0.6" + + +dumpprivkey +----------- +Reveals the private key corresponding to 'address'. Then the importprivkey can be used with this output. + +Syntax: +dumpprivkey "address" + +Arguments: +1. "address" (string, required) The E-CurrencyCoin address for the private key + +Result: +key (string) The private key + +Examples: +1. Dump the private key for "myaddress" + dumpprivkey "myaddress" + + +dumpwallet +---------- +Dumps all wallet keys in a human-readable format. + +Syntax: +dumpwallet "filename" + +Arguments: +1. "filename" (string, required) The filename + +Result: +no output, but it should create a new file with the name specified + +Examples: +1. dump the wallet to a file named test +dumpwallet "test" + + +encryptwallet +------------- +Encrypts the wallet with 'passphrase'. This is for first time encryption. After this, any calls that interact with private keys such as sending or signing will require the passphrase to be set prior the making these calls. Use the walletpassphrase call for this, and then walletlock call. If the wallet is already encrypted, use the walletpassphrasechange call. Note that this will shutdown the server. + +Syntax: +encryptwallet "passphrase" + +Arguments: + "1. "passphrase" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long. + +Result: +no output, but it will shut down the server to finish the process + +Examples: +1. Encrypt you wallet with the password 123abc + encryptwallet "123abc" + + +generate +-------- +Mine blocks immediately (before the RPC call returns). Note: this function can only be used on the regtest network + +Syntax: +generate numblocks + +Arguments: +1. numblocks (numeric, required) How many blocks are generated immediately. + +Result +[ blockhashes ] (array) hashes of blocks generated + +Examples: +1. Generate 11 blocks + generate 11 + + +getaccount +---------- +DEPRECATED. Returns the account associated with the given address. + +Syntax: +getaccount "bitcoinaddress" + +Arguments: +1. "bitcoinaddress" (string, required) The bitcoin address for account lookup. + +Result: +"accountname" (string) the account address + +Examples: +1. Get the account for the address ED1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ + getaccount "ED1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ" + + +getaccountaddress +----------------- +DEPRECATED. Returns the current Bitcoin address for receiving payments to this account. + +Syntax: +"getaccountaddress "account" + +Arguments: +"1. "account" (string, required) The account name for the address. It can also be set to the empty string "" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name. + +Result: + "bitcoinaddress" (string) The account bitcoin address + +Examples: +1. Get address for account myaccount + getaccountaddress "myaccount" + + +getaddednodeinfo +---------------- +Returns information about the given added node, or all added nodes (note that onetry addnodes are not listed here) If dns is false, only a list of added nodes will be provided, otherwise connected information will also be available. + +Syntax: +getaddednodeinfo dns ( "node" ) + +Arguments: +1. dns (boolean, required) If false, only a list of added nodes will be provided, otherwise connected information will also be available. +2. "node" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned. + +Result: +[ + { + "addednode" : "192.168.0.201", (string) The node ip address + "connected" : true|false, (boolean) If connected + "addresses" : [ + { + "address" : "192.168.0.201:8333", (string) The bitcoin server host and port + "connected" : "outbound" (string) connection, inbound or outbound + } + ,... + ] + } + ,... +] + +Examples: +1. Get information about all connected nodes + getaddednodeinfo "true" +2. Get information about the node with ip address 192.168.0.201 + getaddednodeinfo" "true "192.168.0.201" + + +getaddressesbyaccount +--------------------- +DEPRECATED. Returns the list of addresses for the given account. + +Syntax: +getaddressesbyaccount "account" + +Arguments: +1. "account" (string, required) The account name. + +Result: JSON array of string +[ + "bitcoinaddress" (string) a bitcoin address associated with the given account + ,... +] + +Examples: +1. Get the address of the account tabby + getaddressesbyaccount "tabby" + + +getbalance +---------- +If account is not specified, returns the server's total available balance. If account is specified (DEPRECATED), returns the balance in the account. Note that the account "" is not the same as leaving the parameter out. The server total may be different to the balance in the default "" account. + +Syntax: +getbalance ( "account" minconf includeWatchonly ) + +Arguments: +1. "account" (string, optional) DEPRECATED. The selected account, or "*" for entire wallet. It may be the default account using "". +2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times. +3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress') + +Result: +amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account. + +Examples: +1. The total amount in the wallet + getbalance "" +2. The total amount in the wallet at least 5 blocks confirmed + getbalance "*" 6 + + +getbestblockhash +---------------- +Returns the hash of the best (tip) block in the longest block chain. + +Syntax: +getbestblockhash + +Arguments: +none + +Result +"hex" (string) the block hash hex encoded + +Examples +1. Get the best block hash on the longest chain + getbestblockhash + + +getblock +-------- +If verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'. If verbose is true, returns an Object with information about block . + +Syntax: +"getblock "hash" ( verbose ) + +Arguments: +"1. "hash" (string, required) The block hash +"2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data + +Result (for verbose = true): +{ + "hash" : "hash", (string) the block hash (same as provided) + "confirmations" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain + "size" : n, (numeric) The block size + "height" : n, (numeric) The block height or index + "version" : n, (numeric) The block version + "merkleroot" : "xxxx", (string) The merkle root + "tx" : [ (array of string) The transaction ids + "transactionid" (string) The transaction id + ,... + ], + "time" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT) + "mediantime" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT) + "nonce" : n, (numeric) The nonce + "bits" : "1d00ffff", (string) The bits + "difficulty" : x.xxx, (numeric) The difficulty + "chainwork" : "xxxx", (string) Expected number of hashes required to produce the chain up to this block (in hex) + "previousblockhash" : "hash", (string) The hash of the previous block + "nextblockhash" : "hash" (string) The hash of the next block +} + +Result (for verbose=false): +"data" (string) A string that is serialized, hex-encoded data for block 'hash'. + +Examples: +1. get block with hash 00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09 + getblock "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09" + + +getblockchaininfo +----------------- + "getblockchaininfo + "Returns an object containing various state info regarding block chain processing. + Result: + "{ + " "chain": "xxxx", (string) current network name as defined in BIP70 (main, test, regtest) + " "blocks": xxxxxx, (numeric) the current number of blocks processed in the server + " "headers": xxxxxx, (numeric) the current number of headers we have validated + " "bestblockhash": "...", (string) the hash of the currently best block + " "difficulty": xxxxxx, (numeric) the current difficulty + " "mediantime": xxxxxx, (numeric) median time for the current best block + " "verificationprogress": xxxx, (numeric) estimate of verification progress [0..1] + " "chainwork": "xxxx" (string) total amount of work in active chain, in hexadecimal + " "pruned": xx, (boolean) if the blocks are subject to pruning + " "pruneheight": xxxxxx, (numeric) heighest block available + " "softforks": [ (array) status of softforks in progress + " { + " "id": "xxxx", (string) name of softfork + " "version": xx, (numeric) block version + " "enforce": { (object) progress toward enforcing the softfork rules for new-version blocks + " "status": xx, (boolean) true if threshold reached + " "found": xx, (numeric) number of blocks with the new version found + " "required": xx, (numeric) number of blocks required to trigger + " "window": xx, (numeric) maximum size of examined window of recent blocks + " }, + " "reject": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as "enforce") + " }, ... + " ], + " "bip9_softforks": [ (array) status of BIP9 softforks in progress + " { + " "id": "xxxx", (string) name of the softfork + " "status": "xxxx", (string) one of "defined", "started", "lockedin", "active", "failed" + " } + " ] + "} + Examples: + + HelpExampleCli("getblockchaininfo", "") + + +getblockcount +------------- + Returns the number of blocks in the longest block chain. + Result: + "n (numeric) The current block count + Examples: + + HelpExampleCli("getblockcount", "") + + +getblockhash +------------ + "getblockhash index + Returns hash of block in best-block-chain at index provided. + Arguments: + "1. index (numeric, required) The block index + Result: + ""hash" (string) The block hash + Examples: + + HelpExampleCli("getblockhash", "1000") + + +getblockheader +-------------- + "getblockheader "hash" ( verbose ) + If verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'. + "If verbose is true, returns an Object with information about blockheader . + Arguments: + "1. "hash" (string, required) The block hash + "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data + Result (for verbose = true): + "{ + " "hash" : "hash", (string) the block hash (same as provided) + " "confirmations" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain + " "height" : n, (numeric) The block height or index + " "version" : n, (numeric) The block version + " "merkleroot" : "xxxx", (string) The merkle root + " "time" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT) + " "mediantime" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT) + " "nonce" : n, (numeric) The nonce + " "bits" : "1d00ffff", (string) The bits + " "difficulty" : x.xxx, (numeric) The difficulty + " "previousblockhash" : "hash", (string) The hash of the previous block + " "nextblockhash" : "hash", (string) The hash of the next block + " "chainwork" : "0000...1f3" (string) Expected number of hashes required to produce the current chain (in hex) + "} + Result (for verbose=false): + ""data" (string) A string that is serialized, hex-encoded data for block 'hash'. + Examples: + + HelpExampleCli("getblockheader", ""00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"") + + +getblocktemplate +---------------- + "getblocktemplate ( "jsonrequestobject" ) + If the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'. + "It returns data needed to construct a block to work on. + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification. + + Arguments: + "1. "jsonrequestobject" (string, optional) A json object in the following spec + " { + " "mode":"template" (string, optional) This must be set to "template" or omitted + " "capabilities":[ (array, optional) A list of strings + " "support" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid' + " ,... + " ] + " } + " + + Result: + "{ + " "version" : n, (numeric) The block version + " "previousblockhash" : "xxxx", (string) The hash of current highest block + " "transactions" : [ (array) contents of non-coinbase transactions that should be included in the next block + " { + " "data" : "xxxx", (string) transaction data encoded in hexadecimal (byte-for-byte) + " "hash" : "xxxx", (string) hash/id encoded in little-endian hexadecimal + " "depends" : [ (array) array of numbers + " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is + " ,... + " ], + " "fee": n, (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one + " "sigops" : n, (numeric) total number of SigOps, as counted for purposes of block limits; if key is not present, sigop count is unknown and clients MUST NOT assume there aren't any + " "required" : true|false (boolean) if provided and true, this transaction must be in the final block + " } + " ,... + " ], + " "coinbaseaux" : { (json object) data that should be included in the coinbase's scriptSig content + " "flags" : "flags" (string) + " }, + " "coinbasevalue" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis) + " "coinbasetxn" : { ... }, (json object) information for coinbase transaction + " "target" : "xxxx", (string) The hash target + " "mintime" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT) + " "mutable" : [ (array of string) list of ways the block template may be changed + " "value" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock' + " ,... + " ], + " "noncerange" : "00000000ffffffff", (string) A range of valid nonces + " "sigoplimit" : n, (numeric) limit of sigops in blocks + " "sizelimit" : n, (numeric) limit of block size + " "curtime" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT) + " "bits" : "xxx", (string) compressed target of next block + " "height" : n (numeric) The height of the next block + "} + + Examples: + + HelpExampleCli("getblocktemplate", "") + + +getchaintips +------------ + "getchaintips + "Return information about all known tips in the block tree," + " including the main chain as well as orphaned branches. + Result: + "[ + " { + " "height": xxxx, (numeric) height of the chain tip + " "hash": "xxxx", (string) block hash of the tip + " "branchlen": 0 (numeric) zero for main chain + " "status": "active" (string) "active" for the main chain + " }, + " { + " "height": xxxx, + " "hash": "xxxx", + " "branchlen": 1 (numeric) length of branch connecting the tip to the main chain + " "status": "xxxx" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid) + " } + "] + "Possible values for status: + "1. "invalid" This branch contains at least one invalid block + "2. "headers-only" Not all blocks for this branch are available, but the headers are valid + "3. "valid-headers" All blocks are available for this branch, but they were never fully validated + "4. "valid-fork" This branch is not part of the active chain, but is fully validated + "5. "active" This is the tip of the active main chain, which is certainly valid + Examples: + + HelpExampleCli("getchaintips", "") + + +getconnectioncount +------------------ + "getconnectioncount + Returns the number of connections to other nodes. + Result: + "n (numeric) The connection count + Examples: + + HelpExampleCli("getconnectioncount", "") + + +getdifficulty +------------- + "getdifficulty + Returns the proof-of-work difficulty as a multiple of the minimum difficulty. + Result: + "n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty. + Examples: + + HelpExampleCli("getdifficulty", "") + + +getgenerate +----------- + "getgenerate + Return if the server is set to generate coins or not. The default is false. + "It is set with the command line argument -gen (or " + std::string(CONF_FILENAME) + " setting gen) + "It can also be set with the setgenerate call. + Result + "true|false (boolean) If the server is set to generate coins or not + Examples: + + HelpExampleCli("getgenerate", "") + + +getinfo +------- + "getinfo + "Returns an object containing various state info. + Result: + "{ + " "version": xxxxx, (numeric) the server version + " "protocolversion": xxxxx, (numeric) the protocol version + " "walletversion": xxxxx, (numeric) the wallet version + " "balance": xxxxxxx, (numeric) the total E-CurrencyCoin balance of the wallet + " "blocks": xxxxxx, (numeric) the current number of blocks processed in the server + " "timeoffset": xxxxx, (numeric) the time offset + " "connections": xxxxx, (numeric) the number of connections + " "proxy": "host:port", (string, optional) the proxy used by the server + " "difficulty": xxxxxx, (numeric) the current difficulty + " "testnet": true|false, (boolean) if the server is using testnet or not + " "keypoololdest": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool + " "keypoolsize": xxxx, (numeric) how many new keys are pre-generated + " "unlocked_until": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked + " "paytxfee": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB + " "relayfee": x.xxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB + " "errors": "..." (string) any error messages + "} + Examples: + + HelpExampleCli("getinfo", "") + + +getmempoolinfo +-------------- + + + +getmininginfo +------------- + + + +getnewaddress +------------- + + + +getnettotals +------------ + +getnetworkhashps +---------------- + +getnetworkinfo +-------------- + +getpeerinfo +----------- + +getrawchangeaddress +------------------- + +getrawtransaction +----------------- + +getreceivedbyaccount +-------------------- + +getreceivedbyaddress +-------------------- + +getrawmempool +------------- + +gettransaction +-------------- + +gettxout +-------- + +gettxoutproof +------------- + +gettxoutsetinfo +--------------- + +getunconfirmedbalance +--------------------- + +getwalletinfo +------------- + +importaddress +------------- + +importprivkey +------------- + +importpubkey +------------ + +importwallet +------------ + +invalidateblock +--------------- + +keypoolrefill +------------- + +listaccounts +------------ + +listaddressgroupings +-------------------- + +listbanned +---------- + +listlockunspent +--------------- + +listsinceblock +-------------- + +listreceivedbyaccount +--------------------- + +listreceivedbyaddress +--------------------- + +listtransactions +---------------- + +listunspent +----------- + +lockunspent +----------- + +movecmd +------- + +ping +---- + +prioritisetransaction +--------------------- + +reconsiderblock +--------------- + +resendwallettransactions +------------------------ + +setaccount +---------- + +setban +------ + +setgenerate +----------- + +sendfrom +-------- + +sendmany +-------- + +sendrawtransaction +------------------ + +sendtoaddress +------------- + +signmessage +----------- + +signrawtransaction +------------------ + +setmocktime +----------- + +settxfee +-------- + +submitblock +----------- + +walletlock +---------- + +walletpassphrase +---------------- + +walletpassphrasechange +---------------------- + +validateaddress +--------------- + +verifychain +----------- + +verifymessage +------------- + +verifytxoutproof +---------------- diff --git a/eccoin-qt.pro b/eccoin-qt.pro index ba7db980..59f29d7e 100644 --- a/eccoin-qt.pro +++ b/eccoin-qt.pro @@ -1,5 +1,5 @@ fTEMPLATE = app -TARGET = eccoin-windows-daemon +TARGET = eccoind VERSION = 0.7.2 INCLUDEPATH += src src/univalue src/qt DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE @@ -10,8 +10,6 @@ CONFIG += widgets CONFIG += c++11 QT += core gui network widgets -QMAKE_CXXFLAGS = -fpermissive - greaterThan(QT_MAJOR_VERSION, 4) { QT += widgets DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 @@ -26,8 +24,8 @@ win32{ BOOST_LIB_PATH=C:/deps/boost_1_57_0/stage/lib BDB_INCLUDE_PATH=C:/deps/db-4.8.30.NC/build_unix BDB_LIB_PATH=C:/deps/db-4.8.30.NC/build_unix - OPENSSL_INCLUDE_PATH=C:/deps/openssl-1.0.1l/include - OPENSSL_LIB_PATH=C:/deps/openssl-1.0.1l + OPENSSL_INCLUDE_PATH=C:/deps/openssl-1.0.2n/include + OPENSSL_LIB_PATH=C:/deps/openssl-1.0.2n MINIUPNPC_INCLUDE_PATH=C:/deps/ MINIUPNPC_LIB_PATH=C:/deps/miniupnpc/ QRENCODE_INCLUDE_PATH=C:/deps/qrencode-3.4.4 @@ -187,10 +185,6 @@ HEADERS += \ src/arith_uint256.h \ src/base58.h \ src/bloom.h \ - src/chain.h \ - src/chainparams.h \ - src/chainparamsbase.h \ - src/checkpoints.h \ src/checkqueue.h \ src/clientversion.h \ src/coincontrol.h \ @@ -200,7 +194,6 @@ HEADERS += \ src/core_io.h \ src/core_memusage.h \ src/dbwrapper.h \ - src/hash.h \ src/key.h \ src/keystore.h \ src/limitedmap.h \ @@ -230,10 +223,6 @@ HEADERS += \ src/ui_interface.h \ src/uint256.h \ src/undo.h \ - src/util.h \ - src/utilmoneystr.h \ - src/utilstrencodings.h \ - src/utiltime.h \ src/validationinterface.h \ src/version.h \ src/versionbits.h \ @@ -253,8 +242,6 @@ HEADERS += \ src/script/sigcache.h \ src/script/sign.h \ src/script/standard.h \ - src/primitives/block.h \ - src/primitives/transaction.h \ src/policy/fees.h \ src/policy/policy.h \ src/policy/rbf.h \ @@ -278,9 +265,6 @@ HEADERS += \ src/bignum.h \ src/httprpc.h \ src/httpserver.h \ - src/rpcclient.h \ - src/rpcprotocol.h \ - src/rpcserver.h \ src/univalue/univalue.h \ src/univalue/univalue_escapes.h \ src/pbkdf2.h \ @@ -288,7 +272,34 @@ HEADERS += \ src/messages.h \ src/processblock.h \ src/processheader.h \ - src/blockindex.h + src/rpc/rpcclient.h \ + src/rpc/rpcprotocol.h \ + src/rpc/rpcserver.h \ + src/networks/netman.h \ + src/networks/network.h \ + src/chain/chain.h \ + src/chain/block.h \ + src/chain/blockindex.h \ + src/util/util.h \ + src/util/utilmoneystr.h \ + src/util/utilstrencodings.h \ + src/util/utiltime.h \ + src/tx/txout.h \ + src/tx/txin.h \ + src/tx/outpoint.h \ + src/tx/tx.h \ + src/crypto/hash.h \ + src/chain/checkpoints.h \ + src/chain/chainman.h \ + src/signals.h \ + src/networks/networktemplate.h \ + src/tx/servicetx.h \ + src/crypto/chacha20.h \ + src/processtx.h \ + src/verifydb.h \ + src/rpc/events.h \ + src/ans/ans.h \ + src/ans/ansrecord.h # organize compiles of cpp files by section, this seems to be a logical order where the files lower down generally depend @@ -300,17 +311,12 @@ SOURCES += \ src/arith_uint256.cpp \ src/base58.cpp \ src/bloom.cpp \ - src/chain.cpp \ - src/chainparams.cpp \ - src/chainparamsbase.cpp \ - src/checkpoints.cpp \ src/clientversion.cpp \ src/coins.cpp \ src/compressor.cpp \ src/core_read.cpp \ src/core_write.cpp \ src/dbwrapper.cpp \ - src/hash.cpp \ src/key.cpp \ src/keystore.cpp \ src/main.cpp \ @@ -330,10 +336,6 @@ SOURCES += \ src/txdb.cpp \ src/txmempool.cpp \ src/uint256.cpp \ - src/util.cpp \ - src/utilmoneystr.cpp \ - src/utilstrencodings.cpp \ - src/utiltime.cpp \ src/validationinterface.cpp \ src/versionbits.cpp \ src/wallet/crypter.cpp \ @@ -350,8 +352,6 @@ SOURCES += \ src/script/sigcache.cpp \ src/script/sign.cpp \ src/script/standard.cpp \ - src/primitives/block.cpp \ - src/primitives/transaction.cpp \ src/policy/fees.cpp \ src/policy/policy.cpp \ src/policy/rbf.cpp \ @@ -367,31 +367,51 @@ SOURCES += \ src/compat/glibcxx_sanity.cpp \ src/compat/strnlen.cpp \ src/init.cpp \ - src/bitcoind.cpp \ src/crypto/scrypt.cpp \ src/kernel.cpp \ src/httprpc.cpp \ src/httpserver.cpp \ - src/rest.cpp \ - src/rpcblockchain.cpp \ - src/rpcclient.cpp \ - src/rpcmining.cpp \ - src/rpcmisc.cpp \ - src/rpcnet.cpp \ - src/rpcprotocol.cpp \ - src/rpcrawtransaction.cpp \ - src/rpcserver.cpp \ src/univalue/univalue.cpp \ src/univalue/univalue_read.cpp \ src/univalue/univalue_write.cpp \ src/pbkdf2.cpp \ src/script/stakescript.cpp \ - src/rpcdump.cpp \ - src/rpcwallet.cpp \ src/messages.cpp \ src/processblock.cpp \ src/processheader.cpp \ - src/blockindex.cpp + src/rpc/rpcblockchain.cpp \ + src/rpc/rpcclient.cpp \ + src/rpc/rpcdump.cpp \ + src/rpc/rpcmining.cpp \ + src/rpc/rpcprotocol.cpp \ + src/rpc/rpcmisc.cpp \ + src/rpc/rpcnet.cpp \ + src/rpc/rpcwallet.cpp \ + src/rpc/rpcserver.cpp \ + src/rpc/rpcrawtransaction.cpp \ + src/rest.cpp \ + src/networks/netman.cpp \ + src/chain/chain.cpp \ + src/chain/block.cpp \ + src/chain/blockindex.cpp \ + src/util/util.cpp \ + src/util/utilmoneystr.cpp \ + src/util/utilstrencodings.cpp \ + src/util/utiltime.cpp \ + src/tx/txout.cpp \ + src/tx/txin.cpp \ + src/tx/tx.cpp \ + src/crypto/hash.cpp \ + src/chain/checkpoints.cpp \ + src/chain/chainman.cpp \ + src/signals.cpp \ + src/eccoind.cpp \ + src/tx/servicetx.cpp \ + src/crypto/chacha20.cpp \ + src/processtx.cpp \ + src/verifydb.cpp \ + src/ans/ans.cpp \ + src/ans/ansrecord.cpp diff --git a/libbitcoinconsensus.pc.in b/libbitcoinconsensus.pc.in new file mode 100644 index 00000000..eb920c47 --- /dev/null +++ b/libbitcoinconsensus.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: @PACKAGE_NAME@ consensus library +Description: Library for the Bitcoin consensus protocol. +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lbitcoinconsensus +Cflags: -I${includedir} +Requires.private: libcrypto diff --git a/pkg.m4 b/pkg.m4 new file mode 100644 index 00000000..c5b26b52 --- /dev/null +++ b/pkg.m4 @@ -0,0 +1,214 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 1 (pkg-config-0.24) +# +# Copyright © 2004 Scott James Remnant . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +# only at the first occurence in configure.ac, so if the first place +# it's called might be skipped (such as if it is within an "if", you +# have to call PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])# PKG_CHECK_MODULES + + +# PKG_INSTALLDIR(DIRECTORY) +# ------------------------- +# Substitutes the variable pkgconfigdir as the location where a module +# should install pkg-config .pc files. By default the directory is +# $libdir/pkgconfig, but the default can be changed by passing +# DIRECTORY. The user can override through the --with-pkgconfigdir +# parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +]) dnl PKG_INSTALLDIR + + +# PKG_NOARCH_INSTALLDIR(DIRECTORY) +# ------------------------- +# Substitutes the variable noarch_pkgconfigdir as the location where a +# module should install arch-independent pkg-config .pc files. By +# default the directory is $datadir/pkgconfig, but the default can be +# changed by passing DIRECTORY. The user can override through the +# --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +]) dnl PKG_NOARCH_INSTALLDIR + + +# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# ------------------------------------------- +# Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])# PKG_CHECK_VAR diff --git a/qa/README.md b/qa/README.md new file mode 100644 index 00000000..3e0a526d --- /dev/null +++ b/qa/README.md @@ -0,0 +1,68 @@ +The [pull-tester](/qa/pull-tester/) folder contains a script to call +multiple tests from the [rpc-tests](/qa/rpc-tests/) folder. + +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 python3-zmq library is required. On Ubuntu or Debian it can be installed via: +``` +sudo apt-get install python3-zmq +``` + +Running tests +============= + +You can run any single test by calling `qa/pull-tester/rpc-tests.py `. + +Or you can run any combination of tests by calling `qa/pull-tester/rpc-tests.py ...` + +Run the regression test suite with `qa/pull-tester/rpc-tests.py` + +Run all possible tests with `qa/pull-tester/rpc-tests.py -extended` + +Possible options: + +``` + -h, --help show this help message and exit + --nocleanup Leave bitcoinds and test.* datadir on exit or error + --noshutdown Don't stop bitcoinds after the test execution + --srcdir=SRCDIR Source directory containing bitcoind/bitcoin-cli + (default: ../../src) + --tmpdir=TMPDIR Root directory for datadirs + --tracerpc Print out all RPC calls as they are made + --coveragedir=COVERAGEDIR + Write tested RPC commands into this directory +``` + +If you set the environment variable `PYTHON_DEBUG=1` you will get some debug +output (example: `PYTHON_DEBUG=1 qa/pull-tester/rpc-tests.py wallet`). + +A 200-block -regtest blockchain and wallets for four nodes +is created the first time a regression test is run and +is stored in the cache/ directory. Each node has 25 mature +blocks (25*50=1250 BTC) in its wallet. + +After the first run, the cache/ blockchain and wallets are +copied into a temporary directory and used as the initial +test state. + +If you get into a bad state, you should be able +to recover with: + +```bash +rm -rf cache +killall bitcoind +``` + +Writing tests +============= +You are encouraged to write tests for new or existing features. +Further information about the test framework and individual rpc +tests is found in [qa/rpc-tests](/qa/rpc-tests). diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py new file mode 100644 index 00000000..0101bcbe --- /dev/null +++ b/qa/pull-tester/rpc-tests.py @@ -0,0 +1,528 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +""" +Run Regression Test Suite + +This module calls down into individual test cases via subprocess. It will +forward all unrecognized arguments onto the individual test scripts, other +than: + + - `-h` or '--help': print help about all options + - `-extended`: run the "extended" test suite in addition to the basic one. + - `-extended-only`: run ONLY the "extended" test suite + - `-list`: only list the test scripts, do not run. Works in combination + with '-extended' and '-extended-only' too, to print subsets. + - `-win`: signal that this is running in a Windows environment, and we + should run the tests. + - `--coverage`: this generates a basic coverage report for the RPC + interface. + +For more detailed help on options, run with '--help'. + +For a description of arguments recognized by test scripts, see +`qa/pull-tester/test_framework/test_framework.py:BitcoinTestFramework.main`. + +""" +import pdb +import os +import time +import shutil +import signal +import sys +import subprocess +import tempfile +import re + +# to support out-of-source builds, we need to add both the source directory to the path, and the out-of-source directory +# because tests_config is a generated file +sourcePath = os.path.dirname(os.path.realpath(__file__)) +outOfSourceBuildPath = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(sourcePath) +if sourcePath != outOfSourceBuildPath: + sys.path.append(outOfSourceBuildPath) + +from tests_config import * +from test_classes import RpcTest, Disabled, Skip + +BOLD = ("","") +if os.name == 'posix': + # primitive formatting on supported + # terminal via ANSI escape sequences: + BOLD = ('\033[0m', '\033[1m') + +RPC_TESTS_DIR = SRCDIR + '/qa/rpc-tests/' + +#If imported values are not defined then set to zero (or disabled) +if 'ENABLE_WALLET' not in vars(): + ENABLE_WALLET=0 +if 'ENABLE_BITCOIND' not in vars(): + ENABLE_BITCOIND=0 +if 'ENABLE_UTILS' not in vars(): + ENABLE_UTILS=0 +if 'ENABLE_ZMQ' not in vars(): + ENABLE_ZMQ=0 + +ENABLE_COVERAGE=0 + +#Create a set to store arguments and create the passOn string +opts = set() +double_opts = set() # BU: added for checking validity of -- opts +passOn = "" +showHelp = False # if we need to print help +p = re.compile("^--") +p_parallel = re.compile('^-parallel=') +run_parallel = 4 + +# some of the single-dash options applicable only to this runner script +# are also allowed in double-dash format (but are not passed on to the +# test scripts themselves) +private_single_opts = ('-h', + '-f', # equivalent to -force-enable + '-help', + '-list', + '-extended', + '-extended-only', + '-only-extended', + '-force-enable', + '-win') +private_double_opts = ('--list', + '--extended', + '--extended-only', + '--only-extended', + '--force-enable', + '--win') +framework_opts = ('--tracerpc', + '--help', + '--noshutdown', + '--nocleanup', + '--srcdir', + '--tmpdir', + '--coveragedir', + '--randomseed', + '--testbinary', + '--refbinary') +test_script_opts = ('--mineblock', + '--extensive') + +def option_passed(option_without_dashes): + """check if option was specified in single-dash or double-dash format""" + return ('-' + option_without_dashes in opts + or '--' + option_without_dashes in double_opts) + +bold = ("","") +if (os.name == 'posix'): + bold = ('\033[0m', '\033[1m') + +for arg in sys.argv[1:]: + if arg == '--coverage': + ENABLE_COVERAGE = 1 + elif (p.match(arg) or arg in ('-h', '-help')): + if arg not in private_double_opts: + if arg == '--help' or arg == '-help' or arg == '-h': + passOn = '--help' + showHelp = True + else: + if passOn is not '--help': + passOn += " " + arg + # add it to double_opts only for validation + double_opts.add(arg) + elif p_parallel.match(arg): + run_parallel = int(arg.split(sep='=', maxsplit=1)[1]) + + else: + # this is for single-dash options only + # they are interpreted only by this script + opts.add(arg) + +# check for unrecognized options +bad_opts_found = [] +bad_opt_str="Unrecognized option: %s" +for o in opts | double_opts: + if o.startswith('--'): + if o not in framework_opts + test_script_opts + private_double_opts: + print(bad_opt_str % o) + bad_opts_found.append(o) + elif o.startswith('-'): + if o not in private_single_opts: + print(bad_opt_str % o) + bad_opts_found.append(o) + print("Run with -h to get help on usage.") + sys.exit(1) + +#Set env vars +if "BITCOIND" not in os.environ: + os.environ["BITCOIND"] = BUILDDIR + '/src/bitcoind' + EXEEXT +if "BITCOINCLI" not in os.environ: + os.environ["BITCOINCLI"] = BUILDDIR + '/src/bitcoin-cli' + EXEEXT + +#Disable Windows tests by default +if EXEEXT == ".exe" and not option_passed('win'): + print("Win tests currently disabled. Use -win option to enable") + sys.exit(0) + +if not (ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1): + print("No rpc tests to run. Wallet, utils, and bitcoind must all be enabled") + sys.exit(0) + +# python3-zmq may not be installed. Handle this gracefully and with some helpful info +if ENABLE_ZMQ: + try: + import zmq + except ImportError as e: + print("ERROR: \"import zmq\" failed. Set ENABLE_ZMQ=0 or " \ + "to run zmq tests, see dependency info in /qa/README.md.") + raise e + +#Tests +testScripts = [ RpcTest(t) for t in [ + 'bip68-112-113-p2p', + 'validateblocktemplate', + 'parallel', + 'wallet', + 'excessive', + 'buip055', + 'listtransactions', + 'receivedby', + 'mempool_resurrect_test', + 'txn_doublespend --mineblock', + 'txn_clone', + 'getchaintips', + 'rawtransactions', + 'rest', + 'mempool_spendcoinbase', + 'mempool_reorg', + Disabled('mempool_limit', "mempool priority changes causes create_lots_of_big_transactions to fail"), + 'httpbasics', + 'multi_rpc', + 'zapwallettxes', + 'proxy_test', + 'merkle_blocks', + 'fundrawtransaction', + 'signrawtransactions', + 'walletbackup', + 'nodehandling', + 'reindex', + 'decodescript', + Disabled('p2p-fullblocktest', "TODO"), + 'blockchain', + 'disablewallet', + 'sendheaders', + 'keypool', + Disabled('prioritise_transaction', "TODO"), + Disabled('invalidblockrequest', "TODO"), + 'invalidtxrequest', + 'abandonconflict', + 'p2p-versionbits-warning', + 'importprunedfunds', + 'thinblocks' +] ] + +testScriptsExt = [ RpcTest(t) for t in [ + 'txPerf', + 'excessive --extensive', + 'parallel --extensive', + 'bip9-softforks', + 'bip65-cltv', + 'bip65-cltv-p2p', + 'bip68-sequence', + 'bipdersig-p2p', + 'bipdersig', + 'getblocktemplate_longpoll', + 'getblocktemplate_proposals', + 'txn_doublespend', + 'txn_clone --mineblock', + Disabled('pruning', "too much disk"), + 'forknotify', + 'invalidateblock', + Disabled('rpcbind_test', "temporary, bug in libevent, see #6655"), + 'smartfees', + 'maxblocksinflight', + 'p2p-acceptblock', + 'mempool_packages', + 'maxuploadtarget', + Disabled('replace-by-fee', "disabled while Replace By Fee is disabled in code") +] ] + +#Enable ZMQ tests +if ENABLE_ZMQ == 1: + testScripts.append(RpcTest('zmq_test')) + + +def show_wrapper_options(): + """ print command line options specific to wrapper """ + print("Wrapper options:") + print() + print(" -extended/--extended run the extended set of tests") + print(" -only-extended / -extended-only\n" + \ + " --only-extended / --extended-only\n" + \ + " run ONLY the extended tests") + print(" -list / --list only list test names") + print(" -win / --win signal running on Windows and run those tests") + print(" -f / -force-enable / --force-enable\n" + \ + " attempt to run disabled/skipped tests") + print(" -h / -help / --help print this help") + +def runtests(): + global passOn + coverage = None + test_passed = [] + disabled = [] + skipped = [] + tests_to_run = [] + + force_enable = option_passed('force-enable') or '-f' in opts + run_only_extended = option_passed('only-extended') or option_passed('extended-only') + + if option_passed('list'): + if run_only_extended: + for t in testScriptsExt: + print(t) + else: + for t in testScripts: + print(t) + if option_passed('extended'): + for t in testScriptsExt: + print(t) + sys.exit(0) + + if ENABLE_COVERAGE: + coverage = RPCCoverage() + print("Initializing coverage directory at %s\n" % coverage.dir) + + if(ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1): + rpcTestDir = RPC_TESTS_DIR + buildDir = BUILDDIR + run_extended = option_passed('extended') or run_only_extended + cov_flag = coverage.flag if coverage else '' + flags = " --srcdir %s/src %s %s" % (buildDir, cov_flag, passOn) + + # compile the list of tests to check + + # check for explicit tests + if showHelp: + tests_to_run = [ testScripts[0] ] + else: + for o in opts: + if not o.startswith('-'): + found = False + for t in testScripts + testScriptsExt: + t_rep = str(t).split(' ') + if (t_rep[0] == o or t_rep[0] == o + '.py') and len(t_rep) > 1: + # it is a test with args - check all args match what was passed, otherwise don't add this test + t_args = t_rep[1:] + all_args_found = True + for targ in t_args: + if not targ in passOn.split(' '): + all_args_found = False + if all_args_found: + tests_to_run.append(t) + found = True + elif t_rep[0] == o or t_rep[0] == o + '.py': + passOnSplit = [x for x in passOn.split(' ') if x != ''] + found_non_framework_opt = False + for p in passOnSplit: + if p in test_script_opts: + found_non_framework_opt = True + if not found_non_framework_opt: + tests_to_run.append(t) + found = True + if not found: + print("Error: %s is not a known test." % o) + sys.exit(1) + + # if no explicit tests specified, use the lists + if not len(tests_to_run): + if run_only_extended: + tests_to_run = testScriptsExt + else: + tests_to_run += testScripts + if run_extended: + tests_to_run += testScriptsExt + + # weed out the disabled / skipped tests and print them beforehand + # this allows earlier intervention in case a test is unexpectedly + # skipped + if not force_enable: + trimmed_tests_to_run = [] + for t in tests_to_run: + if t.is_disabled(): + print("Disabled testscript %s%s%s (reason: %s)" % (bold[1], t, bold[0], t.reason)) + disabled.append(str(t)) + elif t.is_skipped(): + print("Skipping testscript %s%s%s on this platform (reason: %s)" % (bold[1], t, bold[0], t.reason)) + skipped.append(str(t)) + else: + trimmed_tests_to_run.append(t) + tests_to_run = trimmed_tests_to_run + + if len(tests_to_run) > 1 and run_parallel: + # Populate cache + subprocess.check_output([RPC_TESTS_DIR + 'create_cache.py'] + [flags]) + + tests_to_run = list(map(str,tests_to_run)) + max_len_name = len(max(tests_to_run, key=len)) + time_sum = 0 + time0 = time.time() + job_queue = RPCTestHandler(run_parallel, tests_to_run, flags) + results = BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "PASSED", "DURATION") + BOLD[0] + all_passed = True + + for _ in range(len(tests_to_run)): + (name, stdout, stderr, passed, duration) = job_queue.get_next() + test_passed.append(passed) + all_passed = all_passed and passed + time_sum += duration + + print('\n' + BOLD[1] + name + BOLD[0] + ":") + print(stdout) + print('stderr:\n' if not stderr == '' else '', stderr) + results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration) + print("Pass: %s%s%s, Duration: %s s\n" % (BOLD[1], passed, BOLD[0], duration)) + + results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(6), time_sum) + BOLD[0] + print(results) + print("\nRuntime: %s s" % (int(time.time() - time0))) + + if coverage: + coverage.report_rpc_coverage() + + print("Cleaning up coverage data") + coverage.cleanup() + + if not showHelp: + # show some overall results and aggregates + print() + print("%d test(s) passed / %d test(s) failed / %d test(s) executed" % (test_passed.count(True), + test_passed.count(False), + len(test_passed))) + print("%d test(s) disabled / %d test(s) skipped due to platform" % (len(disabled), len(skipped))) + + # signal that tests have failed using exit code + sys.exit(not all_passed) + + else: + print("No rpc tests to run. Wallet, utils, and bitcoind must all be enabled") + +class RPCTestHandler: + """ + Trigger the testscrips passed in via the list. + """ + + def __init__(self, num_tests_parallel, test_list=None, flags=None): + assert(num_tests_parallel >= 1) + self.num_jobs = num_tests_parallel + self.test_list = test_list + self.flags = flags + self.num_running = 0 + # In case there is a graveyard of zombie bitcoinds, we can apply a + # pseudorandom offset to hopefully jump over them. + # (625 is PORT_RANGE/MAX_NODES) + self.portseed_offset = int(time.time() * 1000) % 625 + self.jobs = [] + + def get_next(self): + while self.num_running < self.num_jobs and self.test_list: + # Add tests + self.num_running += 1 + t = self.test_list.pop(0) + port_seed = ["--portseed={}".format(len(self.test_list) + self.portseed_offset)] + log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16) + log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16) + self.jobs.append((t, + time.time(), + subprocess.Popen((RPC_TESTS_DIR + t).split() + self.flags.split() + port_seed, + universal_newlines=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE))) + if not self.jobs: + raise IndexError('pop from empty list') + while True: + # Return first proc that finishes + time.sleep(.5) + for j in self.jobs: + (name, time0, proc) = j + if os.getenv('TRAVIS') == 'true' and int(time.time() - time0) > 20 * 60: + # In travis, timeout individual tests after 20 minutes (to stop tests hanging and not + # providing useful output. + proc.send_signal(signal.SIGINT) + if proc.poll() is not None: + (stdout, stderr) = proc.communicate(timeout=3) + passed = stderr == "" and proc.returncode == 0 + self.num_running -= 1 + self.jobs.remove(j) + return name, stdout, stderr, passed, int(time.time() - time0) + print('.', end='', flush=True) + +class RPCCoverage(object): + """ + Coverage reporting utilities for pull-tester. + + Coverage calculation works by having each test script subprocess write + coverage files into a particular directory. These files contain the RPC + commands invoked during testing, as well as a complete listing of RPC + commands per `bitcoin-cli help` (`rpc_interface.txt`). + + After all tests complete, the commands run are combined and diff'd against + the complete list to calculate uncovered RPC commands. + + See also: qa/rpc-tests/test_framework/coverage.py + + """ + def __init__(self): + self.dir = tempfile.mkdtemp(prefix="coverage") + self.flag = '--coveragedir %s' % self.dir + + def report_rpc_coverage(self): + """ + Print out RPC commands that were unexercised by tests. + + """ + uncovered = self._get_uncovered_rpc_commands() + + if uncovered: + print("Uncovered RPC commands:") + print("".join((" - %s\n" % i) for i in sorted(uncovered))) + else: + print("All RPC commands covered.") + + def cleanup(self): + return shutil.rmtree(self.dir) + + def _get_uncovered_rpc_commands(self): + """ + Return a set of currently untested RPC commands. + + """ + # This is shared from `qa/rpc-tests/test-framework/coverage.py` + REFERENCE_FILENAME = 'rpc_interface.txt' + COVERAGE_FILE_PREFIX = 'coverage.' + + coverage_ref_filename = os.path.join(self.dir, REFERENCE_FILENAME) + coverage_filenames = set() + all_cmds = set() + covered_cmds = set() + + if not os.path.isfile(coverage_ref_filename): + raise RuntimeError("No coverage reference found") + + with open(coverage_ref_filename, 'r') as f: + all_cmds.update([i.strip() for i in f.readlines()]) + + for root, dirs, files in os.walk(self.dir): + for filename in files: + if filename.startswith(COVERAGE_FILE_PREFIX): + coverage_filenames.add(os.path.join(root, filename)) + + for filename in coverage_filenames: + with open(filename, 'r') as f: + covered_cmds.update([i.strip() for i in f.readlines()]) + + return all_cmds - covered_cmds + + +if __name__ == '__main__': + runtests() diff --git a/qa/pull-tester/run-bitcoind-for-test.sh.in b/qa/pull-tester/run-bitcoind-for-test.sh.in new file mode 100644 index 00000000..dcf26c7a --- /dev/null +++ b/qa/pull-tester/run-bitcoind-for-test.sh.in @@ -0,0 +1,37 @@ +#!/bin/bash +# Copyright (c) 2013-2014 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# +DATADIR="@abs_top_builddir@/.bitcoin" +rm -rf "$DATADIR" +mkdir -p "$DATADIR"/regtest +touch "$DATADIR/regtest/debug.log" +tail -q -n 1 -F "$DATADIR/regtest/debug.log" | grep -m 1 -q "Done loading" & +WAITER=$! +PORT=`expr 10000 + $$ % 55536` +"@abs_top_builddir@/src/bitcoind@EXEEXT@" -connect=0.0.0.0 -datadir="$DATADIR" -rpcuser=user -rpcpassword=pass -listen -keypool=3 -debug -debug=net -logtimestamps -checkmempool=0 -relaypriority=0 -port=$PORT -whitelist=127.0.0.1 -regtest -rpcport=`expr $PORT + 1` & +BITCOIND=$! + +#Install a watchdog. +(sleep 10 && kill -0 $WAITER 2>/dev/null && kill -9 $BITCOIND $$)& +wait $WAITER + +if [ -n "$TIMEOUT" ]; then + timeout "$TIMEOUT"s "$@" $PORT + RETURN=$? +else + "$@" $PORT + RETURN=$? +fi + +(sleep 15 && kill -0 $BITCOIND 2>/dev/null && kill -9 $BITCOIND $$)& +kill $BITCOIND && wait $BITCOIND + +# timeout returns 124 on timeout, otherwise the return value of the child + +# If $RETURN is not 0, the test failed. Dump the tail of the debug log. +if [ $RETURN -ne 0 ]; then tail -n 200 $DATADIR/regtest/debug.log; fi + +exit $RETURN diff --git a/qa/pull-tester/test_classes.py b/qa/pull-tester/test_classes.py new file mode 100644 index 00000000..bc87daad --- /dev/null +++ b/qa/pull-tester/test_classes.py @@ -0,0 +1,131 @@ +# Copyright (c) 2016-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +""" +RpcTest class and help functions which create Disabled/Skipped tests + +>>> sometest=RpcTest("name") +>>> repr(sometest) +'name.py' +>>> sometest.is_disabled() +False +>>> sometest.reason is None +True +>>> sometest.skip_platforms +[] +>>> disabled_test=Disabled("foo", "foo does not work right now") +>>> disabled_test.is_disabled() +True +>>> disabled_test.reason +'foo does not work right now' +>>> disabled_test.skip_platforms +[] +>>> skipped_test=Skip("bar", "", "bar is skipped on all platforms because all matches empty string") +>>> skipped_test.is_skipped() +True +>>> unskipped_test=Skip("baz", "NoSuchPlatform", "baz is not skipped since there is no such platform") +>>> unskipped_test.is_skipped() +False +>>> testwithargs=RpcTest("name --somearg --anotherarg") +>>> repr(testwithargs) +'name.py --somearg --anotherarg' +""" + +import platform + + +# collect as much platform info as we want people to be able to filter +# against for skipped tests +# platform.node() is not included because too easy to get an accidental match +# against a computer's name. +_PLATFORM_INFO = [ platform.machine(), + platform.platform(), + platform.platform(aliased=1), + platform.platform(terse=1), + platform.system(), + ','.join(platform.architecture()), + ','.join(platform.uname()), + ] + + +class RpcTest(object): + ''' Convenience class for RCP tests and disabled/skipped tests ''' + def __init__(self, obj): + if isinstance(obj, RpcTest): + self.name = obj.name + self.args = obj.args + self.disabled = obj.disabled + self.reason = obj.reason + self.skip_platforms = obj.skip_platforms + else: + words = str(obj).split(" ") # need to split args + self.name = words[0] + if len(words) > 1: + self.args = words[1:] + else: + self.args = [] + self.disabled = False + self.reason = None + self.skip_platforms = [] + + def is_disabled(self): + ''' returns True if test is explicitly disabled (completely) ''' + return self.disabled + + def is_skipped(self): + ''' returns True if test would skip on this platform ''' + skip = False + for platform_to_skip in self.skip_platforms: + for pi in _PLATFORM_INFO: + if platform_to_skip.lower() in pi.lower().split(','): + skip = True + break; + return skip + + def disable(self, reason): + ''' set test to explicitly disabled (completely) ''' + self.disabled = True + self.reason = reason + + def skip(self, platforms, reason): + ''' set test to skip on certain platforms ''' + self.reason = reason + if isinstance(platforms, tuple) or isinstance(platforms, list): + for i in platforms: + self.skip_platforms.append(i) + else: + self.skip_platforms.append(platforms) + + def __repr__(self): + retval = self.name + '.py' + if self.args: + retval = " ".join([retval, ] + self.args) + return retval + + def __str__(self): + return repr(self) + + +def Disabled(test_name, reason): + ''' create a disabled test ''' + assert reason, "disabling a test requires a reason!" + rpctest = RpcTest(test_name) + rpctest.disable(reason) + return rpctest + + +def Skip(test_name, platforms, reason): + ''' create a test which is skipped on certain platforms. + The 'platforms' parameter can be a string or tuple/list of strings + which are matched against platform identifiers obtained when + the test is executed. + ''' + assert reason, "skipping a test on some platforms requires a reason!" + rpctest = RpcTest(test_name) + rpctest.skip(platforms, reason) + return rpctest + + +if __name__ == "__main__": + import doctest + doctest.testmod() diff --git a/qa/pull-tester/tests_config.py.in b/qa/pull-tester/tests_config.py.in new file mode 100644 index 00000000..c2d192a7 --- /dev/null +++ b/qa/pull-tester/tests_config.py.in @@ -0,0 +1,15 @@ +#!/usr/bin/env python2 +# Copyright (c) 2013-2014 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +SRCDIR="@abs_top_srcdir@" +BUILDDIR="@abs_top_builddir@" +EXEEXT="@EXEEXT@" + +# These will turn into comments if they were disabled when configuring. +@ENABLE_WALLET_TRUE@ENABLE_WALLET=1 +@BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=1 +@BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=1 +@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=1 diff --git a/qa/rpc-tests/.gitignore b/qa/rpc-tests/.gitignore new file mode 100644 index 00000000..cb41d944 --- /dev/null +++ b/qa/rpc-tests/.gitignore @@ -0,0 +1,2 @@ +*.pyc +cache diff --git a/qa/rpc-tests/README.md b/qa/rpc-tests/README.md new file mode 100644 index 00000000..651b01f1 --- /dev/null +++ b/qa/rpc-tests/README.md @@ -0,0 +1,108 @@ +Regression tests +================ + +### [test_framework/authproxy.py](test_framework/authproxy.py) +Taken from the [python-bitcoinrpc repository](https://github.com/jgarzik/python-bitcoinrpc). + +### [test_framework/test_framework.py](test_framework/test_framework.py) +Base class for new regression tests. + +### [test_framework/util.py](test_framework/util.py) +Generally useful functions. + +### [test_framework/mininode.py](test_framework/mininode.py) +Basic code to support p2p connectivity to a bitcoind. + +### [test_framework/comptool.py](test_framework/comptool.py) +Framework for comparison-tool style, p2p tests. + +### [test_framework/script.py](test_framework/script.py) +Utilities for manipulating transaction scripts (originally from python-bitcoinlib) + +### [test_framework/blockstore.py](test_framework/blockstore.py) +Implements disk-backed block and tx storage. + +### [test_framework/key.py](test_framework/key.py) +Wrapper around OpenSSL EC_Key (originally from python-bitcoinlib) + +### [test_framework/bignum.py](test_framework/bignum.py) +Helpers for script.py + +### [test_framework/blocktools.py](test_framework/blocktools.py) +Helper functions for creating blocks and transactions. + +P2P test design notes +--------------------- + +## Mininode + +* ```mininode.py``` contains all the definitions for objects that pass +over the network (```CBlock```, ```CTransaction```, etc, along with the network-level +wrappers for them, ```msg_block```, ```msg_tx```, etc). + +* P2P tests have two threads. One thread handles all network communication +with the bitcoind(s) being tested (using python's asyncore package); the other +implements the test logic. + +* ```NodeConn``` is the class used to connect to a bitcoind. If you implement +a callback class that derives from ```NodeConnCB``` and pass that to the +```NodeConn``` object, your code will receive the appropriate callbacks when +events of interest arrive. + +* You can pass the same handler to multiple ```NodeConn```'s if you like, or pass +different ones to each -- whatever makes the most sense for your test. + +* Call ```NetworkThread.start()``` after all ```NodeConn``` objects are created to +start the networking thread. (Continue with the test logic in your existing +thread.) + +* RPC calls are available in p2p tests. + +* Can be used to write free-form tests, where specific p2p-protocol behavior +is tested. Examples: ```p2p-accept-block.py```, ```maxblocksinflight.py```. + +## Comptool + +* Testing framework for writing tests that compare the block/tx acceptance +behavior of a bitcoind against 1 or more other bitcoind instances, or against +known outcomes, or both. + +* Set the ```num_nodes``` variable (defined in ```ComparisonTestFramework```) to start up +1 or more nodes. If using 1 node, then ```--testbinary``` can be used as a command line +option to change the bitcoind binary used by the test. If using 2 or more nodes, +then ```--refbinary``` can be optionally used to change the bitcoind that will be used +on nodes 2 and up. + +* Implement a (generator) function called ```get_tests()``` which yields ```TestInstance```s. +Each ```TestInstance``` consists of: + - a list of ```[object, outcome, hash]``` entries + * ```object``` is a ```CBlock```, ```CTransaction```, or + ```CBlockHeader```. ```CBlock```'s and ```CTransaction```'s are tested for + acceptance. ```CBlockHeader```s can be used so that the test runner can deliver + complete headers-chains when requested from the bitcoind, to allow writing + tests where blocks can be delivered out of order but still processed by + headers-first bitcoind's. + * ```outcome``` is ```True```, ```False```, or ```None```. If ```True``` + or ```False```, the tip is compared with the expected tip -- either the + block passed in, or the hash specified as the optional 3rd entry. If + ```None``` is specified, then the test will compare all the bitcoind's + being tested to see if they all agree on what the best tip is. + * ```hash``` is the block hash of the tip to compare against. Optional to + specify; if left out then the hash of the block passed in will be used as + the expected tip. This allows for specifying an expected tip while testing + the handling of either invalid blocks or blocks delivered out of order, + which complete a longer chain. + - ```sync_every_block```: ```True/False```. If ```False```, then all blocks + are inv'ed together, and the test runner waits until the node receives the + last one, and tests only the last block for tip acceptance using the + outcome and specified tip. If ```True```, then each block is tested in + sequence and synced (this is slower when processing many blocks). + - ```sync_every_transaction```: ```True/False```. Analogous to + ```sync_every_block```, except if the outcome on the last tx is "None", + then the contents of the entire mempool are compared across all bitcoind + connections. If ```True``` or ```False```, then only the last tx's + acceptance is tested against the given outcome. + +* For examples of tests written in this framework, see + ```invalidblockrequest.py``` and ```p2p-fullblocktest.py```. + diff --git a/qa/rpc-tests/abandonconflict.py b/qa/rpc-tests/abandonconflict.py new file mode 100644 index 00000000..4e653260 --- /dev/null +++ b/qa/rpc-tests/abandonconflict.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import urllib.parse + +class AbandonConflictTest(BitcoinTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minlimitertxfee=1.0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-logtimemicros"])) + connect_nodes(self.nodes[0], 1) + + def run_test(self): + self.nodes[1].generate(100) + sync_blocks(self.nodes) + balance = self.nodes[0].getbalance() + txA = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) + txB = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) + txC = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) + sync_mempools(self.nodes) + self.nodes[1].generate(1) + + sync_blocks(self.nodes) + newbalance = self.nodes[0].getbalance() + assert(balance - newbalance < Decimal("0.001")) #no more than fees lost + balance = newbalance + + url = urllib.parse.urlparse(self.nodes[1].url) + self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1))) + + # Identify the 10btc outputs + nA = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txA, 1)["vout"]) if vout["value"] == Decimal("10")) + nB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txB, 1)["vout"]) if vout["value"] == Decimal("10")) + nC = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txC, 1)["vout"]) if vout["value"] == Decimal("10")) + + inputs =[] + # spend 10btc outputs from txA and txB + inputs.append({"txid":txA, "vout":nA}) + inputs.append({"txid":txB, "vout":nB}) + outputs = {} + + outputs[self.nodes[0].getnewaddress()] = Decimal("14.99998") + outputs[self.nodes[1].getnewaddress()] = Decimal("5") + signed = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs)) + txAB1 = self.nodes[0].sendrawtransaction(signed["hex"]) + + # Identify the 14.99998btc output + nAB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txAB1, 1)["vout"]) if vout["value"] == Decimal("14.99998")) + + #Create a child tx spending AB1 and C + inputs = [] + inputs.append({"txid":txAB1, "vout":nAB}) + inputs.append({"txid":txC, "vout":nC}) + outputs = {} + outputs[self.nodes[0].getnewaddress()] = Decimal("24.9996") + signed2 = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs)) + txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"]) + + # In mempool txs from self should increase balance from change + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance - Decimal("30") + Decimal("24.9996")) + balance = newbalance + + # Restart the node with a higher min relay fee so the parent tx is no longer in mempool + # TODO: redo with eviction + # Note: had to make sure tx was a considered a free transaction to prevent it from getting into the mempool. + stop_node(self.nodes[0],0) + self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-relaypriority=1", "-minlimitertxfee=10.0"]) + + # Verify txs no longer in mempool + assert(len(self.nodes[0].getrawmempool()) == 0) + + # Not in mempool txs from self should only reduce balance + # 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 + # including that the child tx was also abandoned + self.nodes[0].abandontransaction(txAB1) + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance + Decimal("30")) + balance = newbalance + + # Verify that even with a zero min relay fee, the tx is not reaccepted from wallet on startup once abandoned + stop_node(self.nodes[0],0) + self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minlimitertxfee=0.0"]) + assert(len(self.nodes[0].getrawmempool()) == 0) + assert(self.nodes[0].getbalance() == balance) + + # But if its received again then it is unabandoned + # And since now in mempool, the change is available + # But its child tx remains abandoned + self.nodes[0].sendrawtransaction(signed["hex"]) + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance - Decimal("20") + Decimal("14.99998")) + balance = newbalance + + # Send child tx again so its unabandoned + self.nodes[0].sendrawtransaction(signed2["hex"]) + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance - Decimal("10") - Decimal("14.99998") + Decimal("24.9996")) + balance = newbalance + + # Remove using high relay fee again + stop_node(self.nodes[0],0) + self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-relaypriority=1","-minlimitertxfee=10.0"]) + assert(len(self.nodes[0].getrawmempool()) == 0) + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance - Decimal("24.9996")) + balance = newbalance + + # Create a double spend of AB1 by spending again from only A's 10 output + # Mine double spend from node 1 + inputs =[] + inputs.append({"txid":txA, "vout":nA}) + outputs = {} + outputs[self.nodes[1].getnewaddress()] = Decimal("9.9999") + tx = self.nodes[0].createrawtransaction(inputs, outputs) + signed = self.nodes[0].signrawtransaction(tx) + self.nodes[1].sendrawtransaction(signed["hex"]) + self.nodes[1].generate(1) + + connect_nodes(self.nodes[0], 1) + sync_blocks(self.nodes) + + # Verify that B and C's 10 BTC outputs are available for spending again because AB1 is now conflicted + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance + Decimal("20")) + balance = newbalance + + # There is currently a minor bug around this and so this test doesn't work. See Issue #7315 + # Invalidate the block with the double spend and B's 10 BTC output should no longer be available + # Don't think C's should either + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + newbalance = self.nodes[0].getbalance() + #assert(newbalance == balance - Decimal("10")) + print("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer") + print("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315") + print(str(balance) + " -> " + str(newbalance) + " ?") + +if __name__ == '__main__': + AbandonConflictTest().main() diff --git a/qa/rpc-tests/bip65-cltv-p2p.py b/qa/rpc-tests/bip65-cltv-p2p.py new file mode 100644 index 00000000..60923b9d --- /dev/null +++ b/qa/rpc-tests/bip65-cltv-p2p.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import ComparisonTestFramework +from test_framework.util import * +from test_framework.mininode import CTransaction, NetworkThread +from test_framework.blocktools import create_coinbase, create_block +from test_framework.comptool import TestInstance, TestManager +from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP +from io import BytesIO +import time + +def cltv_invalidate(tx): + '''Modify the signature in vin 0 of the tx to fail CLTV + + Prepends -1 CLTV DROP in the scriptSig itself. + ''' + tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP] + + list(CScript(tx.vin[0].scriptSig))) + +''' +This test is meant to exercise BIP65 (CHECKLOCKTIMEVERIFY) +Connect to a single node. +Mine 2 (version 3) blocks (save the coinbases for later). +Generate 98 more version 3 blocks, verify the node accepts. +Mine 749 version 4 blocks, verify the node accepts. +Check that the new CLTV rules are not enforced on the 750th version 4 block. +Check that the new CLTV rules are enforced on the 751st version 4 block. +Mine 199 new version blocks. +Mine 1 old-version block. +Mine 1 new version block. +Mine 1 old version block, see that the node rejects. +''' + +class BIP65Test(ComparisonTestFramework): + + def __init__(self): + self.num_nodes = 1 + + def setup_network(self): + # Must set the blockversion for this test + self.nodes = start_nodes(1, self.options.tmpdir, + extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=3']], + binary=[self.options.testbinary]) + + def run_test(self): + test = TestManager(self, self.options.tmpdir) + test.add_all_connections(self.nodes) + NetworkThread().start() # Start up network handling in another thread + test.run() + + def create_transaction(self, node, coinbase, to_address, amount): + from_txid = node.getblock(coinbase)['tx'][0] + inputs = [{ "txid" : from_txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + signresult = node.signrawtransaction(rawtx) + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(signresult['hex'])) + tx.deserialize(f) + return tx + + def get_tests(self): + + self.coinbase_blocks = self.nodes[0].generate(2) + height = 3 # height of the next block to build + self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0) + self.nodeaddress = self.nodes[0].getnewaddress() + self.last_block_time = int(time.time()) + + ''' 98 more version 3 blocks ''' + test_blocks = [] + for i in range(98): + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 3 + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance(test_blocks, sync_every_block=False) + + ''' Mine 749 version 4 blocks ''' + test_blocks = [] + for i in range(749): + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 4 + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance(test_blocks, sync_every_block=False) + + ''' + Check that the new CLTV rules are not enforced in the 750th + version 3 block. + ''' + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[0], self.nodeaddress, 1.0) + cltv_invalidate(spendtx) + spendtx.rehash() + + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 4 + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance([[block, True]]) + + ''' + Check that the new CLTV rules are enforced in the 751st version 4 + block. + ''' + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[1], self.nodeaddress, 1.0) + cltv_invalidate(spendtx) + spendtx.rehash() + + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 4 + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + self.last_block_time += 1 + yield TestInstance([[block, False]]) + + ''' Mine 199 new version blocks on last valid tip ''' + test_blocks = [] + for i in range(199): + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 4 + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance(test_blocks, sync_every_block=False) + + ''' Mine 1 old version block ''' + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 3 + block.rehash() + block.solve() + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance([[block, True]]) + + ''' Mine 1 new version block ''' + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 4 + block.rehash() + block.solve() + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance([[block, True]]) + + ''' Mine 1 old version block, should be invalid ''' + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 3 + block.rehash() + block.solve() + self.last_block_time += 1 + yield TestInstance([[block, False]]) + +if __name__ == '__main__': + BIP65Test().main() diff --git a/qa/rpc-tests/bip65-cltv.py b/qa/rpc-tests/bip65-cltv.py new file mode 100644 index 00000000..89f5b1bd --- /dev/null +++ b/qa/rpc-tests/bip65-cltv.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test the CHECKLOCKTIMEVERIFY (BIP65) soft-fork logic +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class BIP65Test(BitcoinTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, [])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=3"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=4"])) + connect_nodes(self.nodes[1], 0) + connect_nodes(self.nodes[2], 0) + self.is_network_split = False + self.sync_all() + + def run_test(self): + cnt = self.nodes[0].getblockcount() + + # Mine some old-version blocks + self.nodes[1].generate(100) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 100): + raise AssertionError("Failed to mine 100 version=3 blocks") + + # Mine 750 new-version blocks + for i in range(15): + self.nodes[2].generate(50) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 850): + raise AssertionError("Failed to mine 750 version=4 blocks") + + # TODO: check that new CHECKLOCKTIMEVERIFY rules are not enforced + + # Mine 1 new-version block + self.nodes[2].generate(1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 851): + raise AssertionError("Failed to mine a version=4 blocks") + + # TODO: check that new CHECKLOCKTIMEVERIFY rules are enforced + + # Mine 198 new-version blocks + for i in range(2): + self.nodes[2].generate(99) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1049): + raise AssertionError("Failed to mine 198 version=4 blocks") + + # Mine 1 old-version block + self.nodes[1].generate(1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1050): + raise AssertionError("Failed to mine a version=3 block after 949 version=4 blocks") + + # Mine 1 new-version blocks + self.nodes[2].generate(1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1051): + raise AssertionError("Failed to mine a version=4 block") + + # Mine 1 old-version blocks + try: + self.nodes[1].generate(1) + raise AssertionError("Succeeded to mine a version=3 block after 950 version=4 blocks") + except JSONRPCException: + pass + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1051): + raise AssertionError("Accepted a version=3 block after 950 version=4 blocks") + + # Mine 1 new-version blocks + self.nodes[2].generate(1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1052): + raise AssertionError("Failed to mine a version=4 block") + +if __name__ == '__main__': + BIP65Test().main() diff --git a/qa/rpc-tests/bip68-112-113-p2p.py b/qa/rpc-tests/bip68-112-113-p2p.py new file mode 100644 index 00000000..6313b5d9 --- /dev/null +++ b/qa/rpc-tests/bip68-112-113-p2p.py @@ -0,0 +1,539 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited 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.test_framework import ComparisonTestFramework +from test_framework.util import * +from test_framework.mininode import ToHex, CTransaction, NetworkThread +from test_framework.blocktools import create_coinbase, create_block +from test_framework.comptool import TestInstance, TestManager +from test_framework.script import * +from io import BytesIO +import time + +''' +This test is meant to exercise activation of the first version bits soft fork +This soft fork will activate the following BIPS: +BIP 68 - nSequence relative lock times +BIP 112 - CHECKSEQUENCEVERIFY +BIP 113 - MedianTimePast semantics for nLockTime + +regtest lock-in with 108/144 block signalling +activation after a further 144 blocks + +mine 82 blocks whose coinbases will be used to generate inputs for our tests +mine 61 blocks to transition from DEFINED to STARTED +mine 144 blocks only 100 of which are signaling readiness in order to fail to change state this period +mine 144 blocks with 108 signaling and verify STARTED->LOCKED_IN +mine 140 blocks and seed block chain with the 82 inputs will use for our tests at height 572 +mine 3 blocks and verify still at LOCKED_IN and test that enforcement has not triggered +mine 1 block and test that enforcement has triggered (which triggers ACTIVE) +Test BIP 113 is enforced +Mine 4 blocks so next height is 580 and test BIP 68 is enforced for time and height +Mine 1 block so next height is 581 and test BIP 68 now passes time but not height +Mine 1 block so next height is 582 and test BIP 68 now passes time and height +Test that BIP 112 is enforced + +Various transactions will be used to test that the BIPs rules are not enforced before the soft fork activates +And that after the soft fork activates transactions pass and fail as they should according to the rules. +For each BIP, transactions of versions 1 and 2 will be tested. +---------------- +BIP 113: +bip113tx - modify the nLocktime variable + +BIP 68: +bip68txs - 16 txs with nSequence relative locktime of 10 with various bits set as per the relative_locktimes below + +BIP 112: +bip112txs_vary_nSequence - 16 txs with nSequence relative_locktimes of 10 evaluated against 10 OP_CSV OP_DROP +bip112txs_vary_nSequence_9 - 16 txs with nSequence relative_locktimes of 9 evaluated against 10 OP_CSV OP_DROP +bip112txs_vary_OP_CSV - 16 txs with nSequence = 10 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP +bip112txs_vary_OP_CSV_9 - 16 txs with nSequence = 9 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP +bip112tx_special - test negative argument to OP_CSV +''' + +base_relative_locktime = 10 +seq_disable_flag = 1<<31 +seq_random_high_bit = 1<<25 +seq_type_flag = 1<<22 +seq_random_low_bit = 1<<18 + +# b31,b25,b22,b18 represent the 31st, 25th, 22nd and 18th bits respectively in the nSequence field +# relative_locktimes[b31][b25][b22][b18] is a base_relative_locktime with the indicated bits set if their indices are 1 +relative_locktimes = [] +for b31 in range(2): + b25times = [] + for b25 in range(2): + b22times = [] + for b22 in range(2): + b18times = [] + for b18 in range(2): + rlt = base_relative_locktime + if (b31): + rlt = rlt | seq_disable_flag + if (b25): + rlt = rlt | seq_random_high_bit + if (b22): + rlt = rlt | seq_type_flag + if (b18): + rlt = rlt | seq_random_low_bit + b18times.append(rlt) + b22times.append(b18times) + b25times.append(b22times) + relative_locktimes.append(b25times) + +def all_rlt_txs(txarray): + txs = [] + for b31 in range(2): + for b25 in range(2): + for b22 in range(2): + for b18 in range(2): + txs.append(txarray[b31][b25][b22][b18]) + return txs + +class BIP68_112_113Test(ComparisonTestFramework): + def __init__(self): + self.num_nodes = 1 + + def setup_network(self): + # Must set the blockversion for this test + self.nodes = start_nodes(1, self.options.tmpdir, + extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=4']], + binary=[self.options.testbinary]) + + def run_test(self): + test = TestManager(self, self.options.tmpdir) + test.add_all_connections(self.nodes) + NetworkThread().start() # Start up network handling in another thread + test.run() + + def send_generic_input_tx(self, node, coinbases): + amount = Decimal("49.99") + return node.sendrawtransaction(ToHex(self.sign_transaction(node, self.create_transaction(node, node.getblock(coinbases.pop())['tx'][0], self.nodeaddress, amount)))) + + def create_transaction(self, node, txid, to_address, amount): + inputs = [{ "txid" : txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(rawtx)) + tx.deserialize(f) + return tx + + def sign_transaction(self, node, unsignedtx): + rawtx = ToHex(unsignedtx) + signresult = node.signrawtransaction(rawtx) + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(signresult['hex'])) + tx.deserialize(f) + return tx + + def generate_blocks(self, number, version, test_blocks = []): + for i in range(number): + block = self.create_test_block([], version) + test_blocks.append([block, True]) + self.last_block_time += 600 + self.tip = block.sha256 + self.tipheight += 1 + return test_blocks + + def create_test_block(self, txs, version = 536870912): + block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600) + block.nVersion = version + block.vtx.extend(txs) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + return block + + def create_bip68txs(self, bip68inputs, txversion, locktime_delta = 0): + txs = [] + assert(len(bip68inputs) >= 16) + i = 0 + for b31 in range(2): + b25txs = [] + for b25 in range(2): + b22txs = [] + for b22 in range(2): + b18txs = [] + for b18 in range(2): + tx = self.create_transaction(self.nodes[0], bip68inputs[i], self.nodeaddress, Decimal("49.98")) + i += 1 + tx.nVersion = txversion + tx.vin[0].nSequence = relative_locktimes[b31][b25][b22][b18] + locktime_delta + b18txs.append(self.sign_transaction(self.nodes[0], tx)) + b22txs.append(b18txs) + b25txs.append(b22txs) + txs.append(b25txs) + return txs + + def create_bip112special(self, input, txversion): + tx = self.create_transaction(self.nodes[0], input, self.nodeaddress, Decimal("49.98")) + tx.nVersion = txversion + signtx = self.sign_transaction(self.nodes[0], tx) + signtx.vin[0].scriptSig = CScript([-1, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig))) + return signtx + + def create_bip112txs(self, bip112inputs, varyOP_CSV, txversion, locktime_delta = 0): + txs = [] + assert(len(bip112inputs) >= 16) + i = 0 + for b31 in range(2): + b25txs = [] + for b25 in range(2): + b22txs = [] + for b22 in range(2): + b18txs = [] + for b18 in range(2): + tx = self.create_transaction(self.nodes[0], bip112inputs[i], self.nodeaddress, Decimal("49.98")) + i += 1 + if (varyOP_CSV): # if varying OP_CSV, nSequence is fixed + tx.vin[0].nSequence = base_relative_locktime + locktime_delta + else: # vary nSequence instead, OP_CSV is fixed + tx.vin[0].nSequence = relative_locktimes[b31][b25][b22][b18] + locktime_delta + tx.nVersion = txversion + signtx = self.sign_transaction(self.nodes[0], tx) + if (varyOP_CSV): + signtx.vin[0].scriptSig = CScript([relative_locktimes[b31][b25][b22][b18], OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig))) + else: + signtx.vin[0].scriptSig = CScript([base_relative_locktime, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig))) + b18txs.append(signtx) + b22txs.append(b18txs) + b25txs.append(b22txs) + txs.append(b25txs) + return txs + + def get_tests(self): + long_past_time = int(time.time()) - 600 * 1000 # enough to build up to 1000 blocks 10 minutes apart without worrying about getting into the future + self.nodes[0].setmocktime(long_past_time - 100) # enough so that the generated blocks will still all be before long_past_time + self.coinbase_blocks = self.nodes[0].generate(1 + 16 + 2*32 + 1) # 82 blocks generated for inputs + self.nodes[0].setmocktime(0) # set time back to present so yielded blocks aren't in the future as we advance last_block_time + self.tipheight = 82 # height of the next block to build + self.last_block_time = long_past_time + self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0) + self.nodeaddress = self.nodes[0].getnewaddress() + + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'defined') + test_blocks = self.generate_blocks(61, 4) + yield TestInstance(test_blocks, sync_every_block=True) # 1 + # Advanced from DEFINED to STARTED, height = 143 + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') + + # Fail to achieve LOCKED_IN 100 out of 144 signal bit 0 + # using a variety of bits to simulate multiple parallel softforks + test_blocks = self.generate_blocks(50, 536870913) # 0x20000001 (signalling ready) + test_blocks = self.generate_blocks(20, 4, test_blocks) # 0x00000004 (signalling not) + test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready) + test_blocks = self.generate_blocks(24, 536936448, test_blocks) # 0x20010000 (signalling not) + yield TestInstance(test_blocks, sync_every_block=False) # 2 + # Failed to advance past STARTED, height = 287 + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') + + # 108 out of 144 signal bit 0 to achieve lock-in + # using a variety of bits to simulate multiple parallel softforks + test_blocks = self.generate_blocks(58, 536870913) # 0x20000001 (signalling ready) + test_blocks = self.generate_blocks(26, 4, test_blocks) # 0x00000004 (signalling not) + test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready) + test_blocks = self.generate_blocks(10, 536936448, test_blocks) # 0x20010000 (signalling not) + yield TestInstance(test_blocks, sync_every_block=False) # 3 + # Advanced from STARTED to LOCKED_IN, height = 431 + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') + + # 140 more version 4 blocks + test_blocks = self.generate_blocks(140, 4) + yield TestInstance(test_blocks, sync_every_block=False) # 4 + + ### Inputs at height = 572 + # Put inputs for all tests in the chain at height 572 (tip now = 571) (time increases by 600s per block) + # Note we reuse inputs for v1 and v2 txs so must test these separately + # 16 normal inputs + bip68inputs = [] + for i in range(16): + bip68inputs.append(self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks)) + # 2 sets of 16 inputs with 10 OP_CSV OP_DROP (actually will be prepended to spending scriptSig) + bip112basicinputs = [] + for j in range(2): + inputs = [] + for i in range(16): + inputs.append(self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks)) + bip112basicinputs.append(inputs) + # 2 sets of 16 varied inputs with (relative_lock_time) OP_CSV OP_DROP (actually will be prepended to spending scriptSig) + bip112diverseinputs = [] + for j in range(2): + inputs = [] + for i in range(16): + inputs.append(self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks)) + bip112diverseinputs.append(inputs) + # 1 special input with -1 OP_CSV OP_DROP (actually will be prepended to spending scriptSig) + bip112specialinput = self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks) + # 1 normal input + bip113input = self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks) + + self.nodes[0].setmocktime(self.last_block_time + 600) + inputblockhash = self.nodes[0].generate(1)[0] # 1 block generated for inputs to be in chain at height 572 + self.nodes[0].setmocktime(0) + self.tip = int("0x" + inputblockhash, 0) + self.tipheight += 1 + self.last_block_time += 600 + assert_equal(len(self.nodes[0].getblock(inputblockhash,True)["tx"]), 82+1) + + # 2 more version 4 blocks + test_blocks = self.generate_blocks(2, 4) + yield TestInstance(test_blocks, sync_every_block=False) # 5 + # Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575) + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') + + # Test both version 1 and version 2 transactions for all tests + # BIP113 test transaction will be modified before each use to put in appropriate block time + bip113tx_v1 = self.create_transaction(self.nodes[0], bip113input, self.nodeaddress, Decimal("49.98")) + bip113tx_v1.vin[0].nSequence = 0xFFFFFFFE + bip113tx_v2 = self.create_transaction(self.nodes[0], bip113input, self.nodeaddress, Decimal("49.98")) + bip113tx_v2.vin[0].nSequence = 0xFFFFFFFE + bip113tx_v2.nVersion = 2 + + # For BIP68 test all 16 relative sequence locktimes + bip68txs_v1 = self.create_bip68txs(bip68inputs, 1) + bip68txs_v2 = self.create_bip68txs(bip68inputs, 2) + + # For BIP112 test: + # 16 relative sequence locktimes of 10 against 10 OP_CSV OP_DROP inputs + bip112txs_vary_nSequence_v1 = self.create_bip112txs(bip112basicinputs[0], False, 1) + bip112txs_vary_nSequence_v2 = self.create_bip112txs(bip112basicinputs[0], False, 2) + # 16 relative sequence locktimes of 9 against 10 OP_CSV OP_DROP inputs + bip112txs_vary_nSequence_9_v1 = self.create_bip112txs(bip112basicinputs[1], False, 1, -1) + bip112txs_vary_nSequence_9_v2 = self.create_bip112txs(bip112basicinputs[1], False, 2, -1) + # sequence lock time of 10 against 16 (relative_lock_time) OP_CSV OP_DROP inputs + bip112txs_vary_OP_CSV_v1 = self.create_bip112txs(bip112diverseinputs[0], True, 1) + bip112txs_vary_OP_CSV_v2 = self.create_bip112txs(bip112diverseinputs[0], True, 2) + # sequence lock time of 9 against 16 (relative_lock_time) OP_CSV OP_DROP inputs + bip112txs_vary_OP_CSV_9_v1 = self.create_bip112txs(bip112diverseinputs[1], True, 1, -1) + bip112txs_vary_OP_CSV_9_v2 = self.create_bip112txs(bip112diverseinputs[1], True, 2, -1) + # -1 OP_CSV OP_DROP input + bip112tx_special_v1 = self.create_bip112special(bip112specialinput, 1) + bip112tx_special_v2 = self.create_bip112special(bip112specialinput, 2) + + + ### TESTING ### + ################################## + ### Before Soft Forks Activate ### + ################################## + # All txs should pass + ### Version 1 txs ### + success_txs = [] + # add BIP113 tx and -1 CSV tx + bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block + bip113signed1 = self.sign_transaction(self.nodes[0], bip113tx_v1) + success_txs.append(bip113signed1) + success_txs.append(bip112tx_special_v1) + # add BIP 68 txs + success_txs.extend(all_rlt_txs(bip68txs_v1)) + # add BIP 112 with seq=10 txs + success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_v1)) + success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_v1)) + # try BIP 112 with seq=9 txs + success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v1)) + success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_9_v1)) + yield TestInstance([[self.create_test_block(success_txs), True]]) # 6 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + ### Version 2 txs ### + success_txs = [] + # add BIP113 tx and -1 CSV tx + bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block + bip113signed2 = self.sign_transaction(self.nodes[0], bip113tx_v2) + success_txs.append(bip113signed2) + success_txs.append(bip112tx_special_v2) + # add BIP 68 txs + success_txs.extend(all_rlt_txs(bip68txs_v2)) + # add BIP 112 with seq=10 txs + success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_v2)) + success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_v2)) + # try BIP 112 with seq=9 txs + success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v2)) + success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_9_v2)) + yield TestInstance([[self.create_test_block(success_txs), True]]) # 7 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + + # 1 more version 4 block to get us to height 575 so the fork should now be active for the next block + test_blocks = self.generate_blocks(1, 4) + yield TestInstance(test_blocks, sync_every_block=False) # 8 + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'active') + + + ################################# + ### After Soft Forks Activate ### + ################################# + ### BIP 113 ### + # BIP 113 tests should now fail regardless of version number if nLockTime isn't satisfied by new rules + bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block + bip113signed1 = self.sign_transaction(self.nodes[0], bip113tx_v1) + bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block + bip113signed2 = self.sign_transaction(self.nodes[0], bip113tx_v2) + for bip113tx in [bip113signed1, bip113signed2]: + yield TestInstance([[self.create_test_block([bip113tx]), False]]) # 9,10 + # BIP 113 tests should now pass if the locktime is < MTP + bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block + bip113signed1 = self.sign_transaction(self.nodes[0], bip113tx_v1) + bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block + bip113signed2 = self.sign_transaction(self.nodes[0], bip113tx_v2) + for bip113tx in [bip113signed1, bip113signed2]: + yield TestInstance([[self.create_test_block([bip113tx]), True]]) # 11,12 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + # Next block height = 580 after 4 blocks of random version + test_blocks = self.generate_blocks(4, 1234) + yield TestInstance(test_blocks, sync_every_block=False) # 13 + + ### BIP 68 ### + ### Version 1 txs ### + # All still pass + success_txs = [] + success_txs.extend(all_rlt_txs(bip68txs_v1)) + yield TestInstance([[self.create_test_block(success_txs), True]]) # 14 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + ### Version 2 txs ### + bip68success_txs = [] + # All txs with SEQUENCE_LOCKTIME_DISABLE_FLAG set pass + for b25 in range(2): + for b22 in range(2): + for b18 in range(2): + bip68success_txs.append(bip68txs_v2[1][b25][b22][b18]) + yield TestInstance([[self.create_test_block(bip68success_txs), True]]) # 15 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + # All txs without flag fail as we are at delta height = 8 < 10 and delta time = 8 * 600 < 10 * 512 + bip68timetxs = [] + for b25 in range(2): + for b18 in range(2): + bip68timetxs.append(bip68txs_v2[0][b25][1][b18]) + for tx in bip68timetxs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 16 - 19 + bip68heighttxs = [] + for b25 in range(2): + for b18 in range(2): + bip68heighttxs.append(bip68txs_v2[0][b25][0][b18]) + for tx in bip68heighttxs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 20 - 23 + + # Advance one block to 581 + test_blocks = self.generate_blocks(1, 1234) + yield TestInstance(test_blocks, sync_every_block=False) # 24 + + # Height txs should fail and time txs should now pass 9 * 600 > 10 * 512 + bip68success_txs.extend(bip68timetxs) + yield TestInstance([[self.create_test_block(bip68success_txs), True]]) # 25 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + for tx in bip68heighttxs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 26 - 29 + + # Advance one block to 582 + test_blocks = self.generate_blocks(1, 1234) + yield TestInstance(test_blocks, sync_every_block=False) # 30 + + # All BIP 68 txs should pass + bip68success_txs.extend(bip68heighttxs) + yield TestInstance([[self.create_test_block(bip68success_txs), True]]) # 31 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + + ### BIP 112 ### + ### Version 1 txs ### + # -1 OP_CSV tx should fail + yield TestInstance([[self.create_test_block([bip112tx_special_v1]), False]]) #32 + # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 1 txs should still pass + success_txs = [] + for b25 in range(2): + for b22 in range(2): + for b18 in range(2): + success_txs.append(bip112txs_vary_OP_CSV_v1[1][b25][b22][b18]) + success_txs.append(bip112txs_vary_OP_CSV_9_v1[1][b25][b22][b18]) + yield TestInstance([[self.create_test_block(success_txs), True]]) # 33 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + # If SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV, version 1 txs should now fail + fail_txs = [] + fail_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_v1)) + fail_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v1)) + for b25 in range(2): + for b22 in range(2): + for b18 in range(2): + fail_txs.append(bip112txs_vary_OP_CSV_v1[0][b25][b22][b18]) + fail_txs.append(bip112txs_vary_OP_CSV_9_v1[0][b25][b22][b18]) + + for tx in fail_txs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 34 - 81 + + ### Version 2 txs ### + # -1 OP_CSV tx should fail + yield TestInstance([[self.create_test_block([bip112tx_special_v2]), False]]) #82 + + # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 2 txs should pass (all sequence locks are met) + success_txs = [] + for b25 in range(2): + for b22 in range(2): + for b18 in range(2): + success_txs.append(bip112txs_vary_OP_CSV_v2[1][b25][b22][b18]) # 8/16 of vary_OP_CSV + success_txs.append(bip112txs_vary_OP_CSV_9_v2[1][b25][b22][b18]) # 8/16 of vary_OP_CSV_9 + + yield TestInstance([[self.create_test_block(success_txs), True]]) # 83 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + ## SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV for all remaining txs ## + # All txs with nSequence 9 should fail either due to earlier mismatch or failing the CSV check + fail_txs = [] + fail_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v2)) # 16/16 of vary_nSequence_9 + for b25 in range(2): + for b22 in range(2): + for b18 in range(2): + fail_txs.append(bip112txs_vary_OP_CSV_9_v2[0][b25][b22][b18]) # 16/16 of vary_OP_CSV_9 + + for tx in fail_txs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 84 - 107 + + # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in nSequence, tx should fail + fail_txs = [] + for b25 in range(2): + for b22 in range(2): + for b18 in range(2): + fail_txs.append(bip112txs_vary_nSequence_v2[1][b25][b22][b18]) # 8/16 of vary_nSequence + for tx in fail_txs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 108-115 + + # If sequencelock types mismatch, tx should fail + fail_txs = [] + for b25 in range(2): + for b18 in range(2): + fail_txs.append(bip112txs_vary_nSequence_v2[0][b25][1][b18]) # 12/16 of vary_nSequence + fail_txs.append(bip112txs_vary_OP_CSV_v2[0][b25][1][b18]) # 12/16 of vary_OP_CSV + for tx in fail_txs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 116-123 + + # Remaining txs should pass, just test masking works properly + success_txs = [] + for b25 in range(2): + for b18 in range(2): + success_txs.append(bip112txs_vary_nSequence_v2[0][b25][0][b18]) # 16/16 of vary_nSequence + success_txs.append(bip112txs_vary_OP_CSV_v2[0][b25][0][b18]) # 16/16 of vary_OP_CSV + yield TestInstance([[self.create_test_block(success_txs), True]]) # 124 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + # Additional test, of checking that comparison of two time types works properly + time_txs = [] + for b25 in range(2): + for b18 in range(2): + tx = bip112txs_vary_OP_CSV_v2[0][b25][1][b18] + tx.vin[0].nSequence = base_relative_locktime | seq_type_flag + signtx = self.sign_transaction(self.nodes[0], tx) + time_txs.append(signtx) + yield TestInstance([[self.create_test_block(time_txs), True]]) # 125 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + ### Missing aspects of test + ## Testing empty stack fails + + +if __name__ == '__main__': + BIP68_112_113Test().main() diff --git a/qa/rpc-tests/bip68-sequence.py b/qa/rpc-tests/bip68-sequence.py new file mode 100644 index 00000000..8adda752 --- /dev/null +++ b/qa/rpc-tests/bip68-sequence.py @@ -0,0 +1,427 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test BIP68 implementation +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.script import * +from test_framework.mininode import * +from test_framework.blocktools import * + +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 +SEQUENCE_LOCKTIME_MASK = 0x0000ffff + +# RPC error for non-BIP68 final transactions +NOT_FINAL_ERROR = "64: non-BIP68-final" + +class BIP68Test(BitcoinTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1", "-debug", "-blockprioritysize=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-whitelist=127.0.0.1", "-debug", "-blockprioritysize=0", "-acceptnonstdtxn=0"])) + self.is_network_split = False + self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"] + connect_nodes(self.nodes[0], 1) + + def run_test(self): + # Generate some coins + self.nodes[0].generate(110) + + print("Running test disable flag") + self.test_disable_flag() + + print("Running test sequence-lock-confirmed-inputs") + self.test_sequence_lock_confirmed_inputs() + + #BU: this test uses prioritisetransaction which has been disabled in BU + #print("Running test sequence-lock-unconfirmed-inputs") + #self.test_sequence_lock_unconfirmed_inputs() + + print("Running test BIP68 not consensus before versionbits activation") + self.test_bip68_not_consensus() + + print("Verifying nVersion=2 transactions aren't standard") + self.test_version2_relay(before_activation=True) + + print("Activating BIP68 (and 112/113)") + self.activateCSV() + + print("Verifying nVersion=2 transactions are now standard") + self.test_version2_relay(before_activation=False) + + print("Passed\n") + + # Test that BIP68 is not in effect if tx version is 1, or if + # the first sequence bit is set. + def test_disable_flag(self): + # Create some unconfirmed inputs + new_addr = self.nodes[0].getnewaddress() + self.nodes[0].sendtoaddress(new_addr, 2) # send 2 BTC + + utxos = self.nodes[0].listunspent(0, 0) + assert(len(utxos) > 0) + + utxo = utxos[0] + + tx1 = CTransaction() + value = int(satoshi_round(utxo["amount"] - self.relayfee)*COIN) + + # Check that the disable flag disables relative locktime. + # If sequence locks were used, this would require 1 block for the + # input to mature. + sequence_value = SEQUENCE_LOCKTIME_DISABLE_FLAG | 1 + tx1.vin = [CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), nSequence=sequence_value)] + tx1.vout = [CTxOut(value, CScript([b'a']))] + + tx1_signed = self.nodes[0].signrawtransaction(ToHex(tx1))["hex"] + tx1_id = self.nodes[0].sendrawtransaction(tx1_signed) + tx1_id = int(tx1_id, 16) + + # This transaction will enable sequence-locks, so this transaction should + # fail + tx2 = CTransaction() + tx2.nVersion = 2 + sequence_value = sequence_value & 0x7fffffff + tx2.vin = [CTxIn(COutPoint(tx1_id, 0), nSequence=sequence_value)] + tx2.vout = [CTxOut(int(value-self.relayfee*COIN), CScript([b'a']))] + tx2.rehash() + + try: + self.nodes[0].sendrawtransaction(ToHex(tx2)) + except JSONRPCException as exp: + assert_equal(exp.error["message"], NOT_FINAL_ERROR) + else: + assert(False) + + # Setting the version back down to 1 should disable the sequence lock, + # so this should be accepted. + tx2.nVersion = 1 + + self.nodes[0].sendrawtransaction(ToHex(tx2)) + + # Calculate the median time past of a prior block ("confirmations" before + # the current tip). + def get_median_time_past(self, confirmations): + block_hash = self.nodes[0].getblockhash(self.nodes[0].getblockcount()-confirmations) + return self.nodes[0].getblockheader(block_hash)["mediantime"] + + # Test that sequence locks are respected for transactions spending confirmed inputs. + def test_sequence_lock_confirmed_inputs(self): + # Create lots of confirmed utxos, and use them to generate lots of random + # transactions. + max_outputs = 50 + addresses = [] + while len(addresses) < max_outputs: + addresses.append(self.nodes[0].getnewaddress()) + while len(self.nodes[0].listunspent()) < 200: + import random + random.shuffle(addresses) + num_outputs = random.randint(1, max_outputs) + outputs = {} + for i in range(num_outputs): + outputs[addresses[i]] = random.randint(1, 20)*0.01 + self.nodes[0].sendmany("", outputs) + self.nodes[0].generate(1) + + utxos = self.nodes[0].listunspent() + + # Try creating a lot of random transactions. + # Each time, choose a random number of inputs, and randomly set + # some of those inputs to be sequence locked (and randomly choose + # between height/time locking). Small random chance of making the locks + # all pass. + for i in range(400): + # Randomly choose up to 10 inputs + num_inputs = random.randint(1, 10) + random.shuffle(utxos) + + # Track whether any sequence locks used should fail + should_pass = True + + # Track whether this transaction was built with sequence locks + using_sequence_locks = False + + tx = CTransaction() + tx.nVersion = 2 + value = 0 + for j in range(num_inputs): + sequence_value = 0xfffffffe # this disables sequence locks + + # 50% chance we enable sequence locks + if random.randint(0,1): + using_sequence_locks = True + + # 10% of the time, make the input sequence value pass + input_will_pass = (random.randint(1,10) == 1) + sequence_value = utxos[j]["confirmations"] + if not input_will_pass: + sequence_value += 1 + should_pass = False + + # Figure out what the median-time-past was for the confirmed input + # Note that if an input has N confirmations, we're going back N blocks + # from the tip so that we're looking up MTP of the block + # PRIOR to the one the input appears in, as per the BIP68 spec. + orig_time = self.get_median_time_past(utxos[j]["confirmations"]) + cur_time = self.get_median_time_past(0) # MTP of the tip + + # can only timelock this input if it's not too old -- otherwise use height + can_time_lock = True + if ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY) >= SEQUENCE_LOCKTIME_MASK: + can_time_lock = False + + # if time-lockable, then 50% chance we make this a time lock + if random.randint(0,1) and can_time_lock: + # Find first time-lock value that fails, or latest one that succeeds + time_delta = sequence_value << SEQUENCE_LOCKTIME_GRANULARITY + if input_will_pass and time_delta > cur_time - orig_time: + sequence_value = ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY) + elif (not input_will_pass and time_delta <= cur_time - orig_time): + sequence_value = ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY)+1 + sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG + tx.vin.append(CTxIn(COutPoint(int(utxos[j]["txid"], 16), utxos[j]["vout"]), nSequence=sequence_value)) + value += utxos[j]["amount"]*COIN + # Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output + tx_size = len(ToHex(tx))//2 + 120*num_inputs + 50 + tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), CScript([b'a']))) + rawtx = self.nodes[0].signrawtransaction(ToHex(tx))["hex"] + + try: + self.nodes[0].sendrawtransaction(rawtx) + except JSONRPCException as exp: + assert(not should_pass and using_sequence_locks) + assert_equal(exp.error["message"], NOT_FINAL_ERROR) + else: + assert(should_pass or not using_sequence_locks) + # Recalculate utxos if we successfully sent the transaction + utxos = self.nodes[0].listunspent() + + # Test that sequence locks on unconfirmed inputs must have nSequence + # height or time of 0 to be accepted. + # Then test that BIP68-invalid transactions are removed from the mempool + # after a reorg. + def test_sequence_lock_unconfirmed_inputs(self): + # Store height so we can easily reset the chain at the end of the test + cur_height = self.nodes[0].getblockcount() + + # Create a mempool tx. + txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2) + tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid)) + tx1.rehash() + + # Anyone-can-spend mempool tx. + # Sequence lock of 0 should pass. + tx2 = CTransaction() + tx2.nVersion = 2 + tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)] + tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))] + tx2_raw = self.nodes[0].signrawtransaction(ToHex(tx2))["hex"] + tx2 = FromHex(tx2, tx2_raw) + tx2.rehash() + + self.nodes[0].sendrawtransaction(tx2_raw) + + # Create a spend of the 0th output of orig_tx with a sequence lock + # of 1, and test what happens when submitting. + # orig_tx.vout[0] must be an anyone-can-spend output + def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock): + sequence_value = 1 + if not use_height_lock: + sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG + + tx = CTransaction() + tx.nVersion = 2 + tx.vin = [CTxIn(COutPoint(orig_tx.sha256, 0), nSequence=sequence_value)] + tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee*COIN), CScript([b'a']))] + tx.rehash() + + try: + node.sendrawtransaction(ToHex(tx)) + except JSONRPCException as exp: + assert_equal(exp.error["message"], NOT_FINAL_ERROR) + assert(orig_tx.hash in node.getrawmempool()) + else: + # orig_tx must not be in mempool + assert(orig_tx.hash not in node.getrawmempool()) + return tx + + test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True) + test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False) + + # Now mine some blocks, but make sure tx2 doesn't get mined. + # Use prioritisetransaction to lower the effective feerate to 0 + self.nodes[0].prioritisetransaction(tx2.hash, -1e15, int(-self.relayfee*COIN)) + cur_time = int(time.time()) + for i in range(10): + self.nodes[0].setmocktime(cur_time + 600) + self.nodes[0].generate(1) + cur_time += 600 + + assert(tx2.hash in self.nodes[0].getrawmempool()) + + test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True) + test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False) + + # Mine tx2, and then try again + self.nodes[0].prioritisetransaction(tx2.hash, 1e15, int(self.relayfee*COIN)) + + # Advance the time on the node so that we can test timelocks + self.nodes[0].setmocktime(cur_time+600) + self.nodes[0].generate(1) + assert(tx2.hash not in self.nodes[0].getrawmempool()) + + # Now that tx2 is not in the mempool, a sequence locked spend should + # succeed + tx3 = test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False) + assert(tx3.hash in self.nodes[0].getrawmempool()) + + self.nodes[0].generate(1) + assert(tx3.hash not in self.nodes[0].getrawmempool()) + + # One more test, this time using height locks + tx4 = test_nonzero_locks(tx3, self.nodes[0], self.relayfee, use_height_lock=True) + assert(tx4.hash in self.nodes[0].getrawmempool()) + + # Now try combining confirmed and unconfirmed inputs + tx5 = test_nonzero_locks(tx4, self.nodes[0], self.relayfee, use_height_lock=True) + assert(tx5.hash not in self.nodes[0].getrawmempool()) + + utxos = self.nodes[0].listunspent() + tx5.vin.append(CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["vout"]), nSequence=1)) + tx5.vout[0].nValue += int(utxos[0]["amount"]*COIN) + raw_tx5 = self.nodes[0].signrawtransaction(ToHex(tx5))["hex"] + + try: + self.nodes[0].sendrawtransaction(raw_tx5) + except JSONRPCException as exp: + assert_equal(exp.error["message"], NOT_FINAL_ERROR) + else: + assert(False) + + # Test mempool-BIP68 consistency after reorg + # + # State of the transactions in the last blocks: + # ... -> [ tx2 ] -> [ tx3 ] + # tip-1 tip + # And currently tx4 is in the mempool. + # + # If we invalidate the tip, tx3 should get added to the mempool, causing + # tx4 to be removed (fails sequence-lock). + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + assert(tx4.hash not in self.nodes[0].getrawmempool()) + assert(tx3.hash in self.nodes[0].getrawmempool()) + + # Now mine 2 empty blocks to reorg out the current tip (labeled tip-1 in + # diagram above). + # This would cause tx2 to be added back to the mempool, which in turn causes + # tx3 to be removed. + tip = int(self.nodes[0].getblockhash(self.nodes[0].getblockcount()-1), 16) + height = self.nodes[0].getblockcount() + for i in range(2): + block = create_block(tip, create_coinbase(height), cur_time) + block.nVersion = 3 + block.rehash() + block.solve() + tip = block.sha256 + height += 1 + self.nodes[0].submitblock(ToHex(block)) + cur_time += 1 + + mempool = self.nodes[0].getrawmempool() + assert(tx3.hash not in mempool) + assert(tx2.hash in mempool) + + # Reset the chain and get rid of the mocktimed-blocks + self.nodes[0].setmocktime(0) + self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height+1)) + self.nodes[0].generate(10) + + # Make sure that BIP68 isn't being used to validate blocks, prior to + # versionbits activation. If more blocks are mined prior to this test + # being run, then it's possible the test has activated the soft fork, and + # this test should be moved to run earlier, or deleted. + def test_bip68_not_consensus(self): + assert(get_bip9_status(self.nodes[0], 'csv')['status'] != 'active') + txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2) + + tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid)) + tx1.rehash() + + # Make an anyone-can-spend transaction + tx2 = CTransaction() + tx2.nVersion = 1 + tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)] + tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))] + + # sign tx2 + tx2_raw = self.nodes[0].signrawtransaction(ToHex(tx2))["hex"] + tx2 = FromHex(tx2, tx2_raw) + tx2.rehash() + + self.nodes[0].sendrawtransaction(ToHex(tx2)) + + # Now make an invalid spend of tx2 according to BIP68 + sequence_value = 100 # 100 block relative locktime + + tx3 = CTransaction() + tx3.nVersion = 2 + tx3.vin = [CTxIn(COutPoint(tx2.sha256, 0), nSequence=sequence_value)] + tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))] + tx3.rehash() + + try: + self.nodes[0].sendrawtransaction(ToHex(tx3)) + except JSONRPCException as exp: + assert_equal(exp.error["message"], NOT_FINAL_ERROR) + else: + assert(False) + + # make a block that violates bip68; ensure that the tip updates + tip = int(self.nodes[0].getbestblockhash(), 16) + block = create_block(tip, create_coinbase(self.nodes[0].getblockcount()+1)) + block.nVersion = 3 + block.vtx.extend([tx1, tx2, tx3]) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + + self.nodes[0].submitblock(ToHex(block)) + assert_equal(self.nodes[0].getbestblockhash(), block.hash) + + def activateCSV(self): + # activation should happen at block height 432 (3 periods) + min_activation_height = 432 + height = self.nodes[0].getblockcount() + assert(height < 432) + self.nodes[0].generate(432-height) + assert(get_bip9_status(self.nodes[0], 'csv')['status'] == 'active') + sync_blocks(self.nodes) + + # Use self.nodes[1] to test standardness relay policy + def test_version2_relay(self, before_activation): + inputs = [ ] + outputs = { self.nodes[1].getnewaddress() : 1.0 } + rawtx = self.nodes[1].createrawtransaction(inputs, outputs) + rawtxfund = self.nodes[1].fundrawtransaction(rawtx)['hex'] + tx = FromHex(CTransaction(), rawtxfund) + tx.nVersion = 2 + tx_signed = self.nodes[1].signrawtransaction(ToHex(tx))["hex"] + try: + tx_id = self.nodes[1].sendrawtransaction(tx_signed) + assert(before_activation == False) + except: + assert(before_activation) + + +if __name__ == '__main__': + BIP68Test().main() diff --git a/qa/rpc-tests/bip9-softforks.py b/qa/rpc-tests/bip9-softforks.py new file mode 100644 index 00000000..f5894738 --- /dev/null +++ b/qa/rpc-tests/bip9-softforks.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited 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.util import sync_blocks +from test_framework.test_framework import ComparisonTestFramework +from test_framework.util import * +from test_framework.mininode import CTransaction, NetworkThread +from test_framework.blocktools import create_coinbase, create_block +from test_framework.comptool import TestInstance, TestManager +from test_framework.script import CScript, OP_1NEGATE, OP_CHECKSEQUENCEVERIFY, OP_DROP +from io import BytesIO +import time +import itertools + +''' +This test is meant to exercise BIP forks +Connect to a single node. +regtest lock-in with 108/144 block signalling +activation after a further 144 blocks +mine 2 block and save coinbases for later use +mine 141 blocks to transition from DEFINED to STARTED +mine 100 blocks signalling readiness and 44 not in order to fail to change state this period +mine 108 blocks signalling readiness and 36 blocks not signalling readiness (STARTED->LOCKED_IN) +mine a further 143 blocks (LOCKED_IN) +test that enforcement has not triggered (which triggers ACTIVE) +test that enforcement has triggered +''' + + +class BIP9SoftForksTest(ComparisonTestFramework): + + def __init__(self): + self.num_nodes = 1 + + def setup_network(self): + self.nodes = start_nodes(1, self.options.tmpdir, + extra_args=[['-debug', '-whitelist=127.0.0.1']], + binary=[self.options.testbinary]) + + def run_test(self): + self.test = TestManager(self, self.options.tmpdir) + self.test.add_all_connections(self.nodes) + NetworkThread().start() # Start up network handling in another thread + self.test.run() + + def create_transaction(self, node, coinbase, to_address, amount): + from_txid = node.getblock(coinbase)['tx'][0] + inputs = [{ "txid" : from_txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(rawtx)) + tx.deserialize(f) + tx.nVersion = 2 + return tx + + def sign_transaction(self, node, tx): + signresult = node.signrawtransaction(bytes_to_hex_str(tx.serialize())) + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(signresult['hex'])) + tx.deserialize(f) + return tx + + def generate_blocks(self, number, version, test_blocks = []): + for i in range(number): + block = create_block(self.tip, create_coinbase(self.height), self.last_block_time + 1) + block.nVersion = version + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + self.height += 1 + return test_blocks + + def get_bip9_status(self, key): + info = self.nodes[0].getblockchaininfo() + return info['bip9_softforks'][key] + + def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignature, bitno): + # generate some coins for later + self.coinbase_blocks = self.nodes[0].generate(2) + self.height = 3 # height of the next block to build + self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0) + self.nodeaddress = self.nodes[0].getnewaddress() + self.last_block_time = int(time.time()) + + assert_equal(self.get_bip9_status(bipName)['status'], 'defined') + tmpl = self.nodes[0].getblocktemplate({}) + assert(bipName not in tmpl['rules']) + assert(bipName not in tmpl['vbavailable']) + assert_equal(tmpl['vbrequired'], 0) + assert_equal(tmpl['version'], 0x20000000) + + # Test 1 + # Advance from DEFINED to STARTED + test_blocks = self.generate_blocks(141, 4) + yield TestInstance(test_blocks, sync_every_block=False) + + assert_equal(self.get_bip9_status(bipName)['status'], 'started') + tmpl = self.nodes[0].getblocktemplate({}) + assert(bipName not in tmpl['rules']) + assert_equal(tmpl['vbavailable'][bipName], bitno) + assert_equal(tmpl['vbrequired'], 0) + assert(tmpl['version'] & activated_version) + + # Test 2 + # Fail to achieve LOCKED_IN 100 out of 144 signal bit 1 + # using a variety of bits to simulate multiple parallel softforks + test_blocks = self.generate_blocks(50, activated_version) # 0x20000001 (signalling ready) + test_blocks = self.generate_blocks(20, 4, test_blocks) # 0x00000004 (signalling not) + test_blocks = self.generate_blocks(50, activated_version, test_blocks) # 0x20000101 (signalling ready) + test_blocks = self.generate_blocks(24, 4, test_blocks) # 0x20010000 (signalling not) + yield TestInstance(test_blocks, sync_every_block=False) + + assert_equal(self.get_bip9_status(bipName)['status'], 'started') + tmpl = self.nodes[0].getblocktemplate({}) + assert(bipName not in tmpl['rules']) + assert_equal(tmpl['vbavailable'][bipName], bitno) + assert_equal(tmpl['vbrequired'], 0) + assert(tmpl['version'] & activated_version) + + # Test 3 + # 108 out of 144 signal bit 1 to achieve LOCKED_IN + # using a variety of bits to simulate multiple parallel softforks + test_blocks = self.generate_blocks(58, activated_version) # 0x20000001 (signalling ready) + test_blocks = self.generate_blocks(26, 4, test_blocks) # 0x00000004 (signalling not) + test_blocks = self.generate_blocks(50, activated_version, test_blocks) # 0x20000101 (signalling ready) + test_blocks = self.generate_blocks(10, 4, test_blocks) # 0x20010000 (signalling not) + yield TestInstance(test_blocks, sync_every_block=False) + + assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in') + tmpl = self.nodes[0].getblocktemplate({}) + assert(bipName not in tmpl['rules']) + + # Test 4 + # 143 more version 536870913 blocks (waiting period-1) + test_blocks = self.generate_blocks(143, 4) + yield TestInstance(test_blocks, sync_every_block=False) + + assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in') + tmpl = self.nodes[0].getblocktemplate({}) + assert(bipName not in tmpl['rules']) + + # Test 5 + # Check that the new rule is enforced + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[0], self.nodeaddress, 1.0) + invalidate(spendtx) + spendtx = self.sign_transaction(self.nodes[0], spendtx) + spendtx.rehash() + invalidatePostSignature(spendtx) + spendtx.rehash() + block = create_block(self.tip, create_coinbase(self.height), self.last_block_time + 1) + block.nVersion = activated_version + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + + self.last_block_time += 1 + self.tip = block.sha256 + self.height += 1 + yield TestInstance([[block, True]]) + + assert_equal(self.get_bip9_status(bipName)['status'], 'active') + tmpl = self.nodes[0].getblocktemplate({}) + assert(bipName in tmpl['rules']) + assert(bipName not in tmpl['vbavailable']) + assert_equal(tmpl['vbrequired'], 0) + assert(not (tmpl['version'] & (1 << bitno))) + + # Test 6 + # Check that the new sequence lock rules are enforced + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[1], self.nodeaddress, 1.0) + invalidate(spendtx) + spendtx = self.sign_transaction(self.nodes[0], spendtx) + spendtx.rehash() + invalidatePostSignature(spendtx) + spendtx.rehash() + + block = create_block(self.tip, create_coinbase(self.height), self.last_block_time + 1) + block.nVersion = 5 + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + self.last_block_time += 1 + yield TestInstance([[block, False]]) + # Restart all + stop_nodes(self.nodes) + wait_bitcoinds() + shutil.rmtree(self.options.tmpdir) + self.setup_chain() + self.setup_network() + self.test.clear_all_connections() + self.test.add_all_connections(self.nodes) + NetworkThread().start() # Start up network handling in another thread + + + def get_tests(self): + for test in itertools.chain( + self.test_BIP('csv', 0x20000001, self.sequence_lock_invalidate, self.donothing, 0), + self.test_BIP('csv', 0x20000001, self.mtp_invalidate, self.donothing, 0), + self.test_BIP('csv', 0x20000001, self.donothing, self.csv_invalidate, 0) + ): + yield test + + def donothing(self, tx): + return + + def csv_invalidate(self, tx): + '''Modify the signature in vin 0 of the tx to fail CSV + Prepends -1 CSV DROP in the scriptSig itself. + ''' + tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKSEQUENCEVERIFY, OP_DROP] + + list(CScript(tx.vin[0].scriptSig))) + + def sequence_lock_invalidate(self, tx): + '''Modify the nSequence to make it fails once sequence lock rule is activated (high timespan) + ''' + tx.vin[0].nSequence = 0x00FFFFFF + tx.nLockTime = 0 + + def mtp_invalidate(self, tx): + '''Modify the nLockTime to make it fails once MTP rule is activated + ''' + # Disable Sequence lock, Activate nLockTime + tx.vin[0].nSequence = 0x90FFFFFF + tx.nLockTime = self.last_block_time + +if __name__ == '__main__': + BIP9SoftForksTest().main() diff --git a/qa/rpc-tests/bipdersig-p2p.py b/qa/rpc-tests/bipdersig-p2p.py new file mode 100644 index 00000000..e00c3c43 --- /dev/null +++ b/qa/rpc-tests/bipdersig-p2p.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import ComparisonTestFramework +from test_framework.util import * +from test_framework.mininode import CTransaction, NetworkThread +from test_framework.blocktools import create_coinbase, create_block +from test_framework.comptool import TestInstance, TestManager +from test_framework.script import CScript +from io import BytesIO +import time + +# A canonical signature consists of: +# <30> <02> <02> +def unDERify(tx): + ''' + Make the signature in vin 0 of a tx non-DER-compliant, + by adding padding after the S-value. + ''' + scriptSig = CScript(tx.vin[0].scriptSig) + newscript = [] + for i in scriptSig: + if (len(newscript) == 0): + newscript.append(i[0:-1] + b'\0' + i[-1:]) + else: + newscript.append(i) + tx.vin[0].scriptSig = CScript(newscript) + +''' +This test is meant to exercise BIP66 (DER SIG). +Connect to a single node. +Mine 2 (version 2) blocks (save the coinbases for later). +Generate 98 more version 2 blocks, verify the node accepts. +Mine 749 version 3 blocks, verify the node accepts. +Check that the new DERSIG rules are not enforced on the 750th version 3 block. +Check that the new DERSIG rules are enforced on the 751st version 3 block. +Mine 199 new version blocks. +Mine 1 old-version block. +Mine 1 new version block. +Mine 1 old version block, see that the node rejects. +''' + +class BIP66Test(ComparisonTestFramework): + + def __init__(self): + self.num_nodes = 1 + + def setup_network(self): + # Must set the blockversion for this test + self.nodes = start_nodes(1, self.options.tmpdir, + extra_args=[['-use-thinblocks=0', '-debug', '-whitelist=127.0.0.1', '-blockversion=2']], + binary=[self.options.testbinary]) + + def run_test(self): + test = TestManager(self, self.options.tmpdir) + test.add_all_connections(self.nodes) + NetworkThread().start() # Start up network handling in another thread + test.run() + + def create_transaction(self, node, coinbase, to_address, amount): + from_txid = node.getblock(coinbase)['tx'][0] + inputs = [{ "txid" : from_txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + signresult = node.signrawtransaction(rawtx) + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(signresult['hex'])) + tx.deserialize(f) + return tx + + def get_tests(self): + + self.coinbase_blocks = self.nodes[0].generate(2) + height = 3 # height of the next block to build + self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0) + self.nodeaddress = self.nodes[0].getnewaddress() + self.last_block_time = int(time.time()) + + ''' 98 more version 2 blocks ''' + test_blocks = [] + for i in range(98): + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 2 + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance(test_blocks, sync_every_block=False) + + ''' Mine 749 version 3 blocks ''' + test_blocks = [] + for i in range(749): + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 3 + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance(test_blocks, sync_every_block=True) + + ''' + Check that the new DERSIG rules are not enforced in the 750th + version 3 block. + ''' + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[0], self.nodeaddress, 1.0) + unDERify(spendtx) + spendtx.rehash() + + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 3 + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance([[block, True]]) + + ''' + Check that the new DERSIG rules are enforced in the 751st version 3 + block. + ''' + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[1], self.nodeaddress, 1.0) + unDERify(spendtx) + spendtx.rehash() + + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 3 + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + self.last_block_time += 1 + yield TestInstance([[block, False]]) + + ''' Mine 199 new version blocks on last valid tip ''' + test_blocks = [] + for i in range(199): + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 3 + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance(test_blocks, sync_every_block=False) + + ''' Mine 1 old version block ''' + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 2 + block.rehash() + block.solve() + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance([[block, True]]) + + ''' Mine 1 new version block ''' + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 3 + block.rehash() + block.solve() + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance([[block, True]]) + + ''' Mine 1 old version block, should be invalid ''' + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 2 + block.rehash() + block.solve() + self.last_block_time += 1 + yield TestInstance([[block, False]]) + +if __name__ == '__main__': + BIP66Test().main() diff --git a/qa/rpc-tests/bipdersig.py b/qa/rpc-tests/bipdersig.py new file mode 100644 index 00000000..12403a15 --- /dev/null +++ b/qa/rpc-tests/bipdersig.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test the BIP66 changeover logic +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class BIP66Test(BitcoinTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, [])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=2"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=3"])) + connect_nodes(self.nodes[1], 0) + connect_nodes(self.nodes[2], 0) + self.is_network_split = False + self.sync_all() + + def run_test(self): + cnt = self.nodes[0].getblockcount() + + # Mine some old-version blocks + self.nodes[1].generate(100) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 100): + raise AssertionError("Failed to mine 100 version=2 blocks") + + # Mine 750 new-version blocks + for i in range(15): + self.nodes[2].generate(50) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 850): + raise AssertionError("Failed to mine 750 version=3 blocks") + + # TODO: check that new DERSIG rules are not enforced + + # Mine 1 new-version block + self.nodes[2].generate(1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 851): + raise AssertionError("Failed to mine a version=3 blocks") + + # TODO: check that new DERSIG rules are enforced + + # Mine 198 new-version blocks + for i in range(2): + self.nodes[2].generate(99) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1049): + raise AssertionError("Failed to mine 198 version=3 blocks") + + # Mine 1 old-version block + self.nodes[1].generate(1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1050): + raise AssertionError("Failed to mine a version=2 block after 949 version=3 blocks") + + # Mine 1 new-version blocks + self.nodes[2].generate(1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1051): + raise AssertionError("Failed to mine a version=3 block") + + # Mine 1 old-version blocks + try: + self.nodes[1].generate(1) + raise AssertionError("Succeeded to mine a version=2 block after 950 version=3 blocks") + except JSONRPCException: + pass + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1051): + raise AssertionError("Accepted a version=2 block after 950 version=3 blocks") + + # Mine 1 new-version blocks + self.nodes[2].generate(1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1052): + raise AssertionError("Failed to mine a version=3 block") + +if __name__ == '__main__': + BIP66Test().main() diff --git a/qa/rpc-tests/blockchain.py b/qa/rpc-tests/blockchain.py new file mode 100644 index 00000000..5576b21e --- /dev/null +++ b/qa/rpc-tests/blockchain.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test RPC calls related to blockchain state. Tests correspond to code in +# rpc/blockchain.cpp. +# + +from decimal import Decimal + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.authproxy import JSONRPCException +from test_framework.util import ( + initialize_chain, + assert_equal, + assert_raises, + assert_is_hex_string, + assert_is_hash_string, + start_nodes, + connect_nodes_bi, +) + + +class BlockchainTest(BitcoinTestFramework): + """ + Test blockchain-related RPC calls: + + - gettxoutsetinfo + - verifychain + + """ + + def setup_chain(self): + print("Initializing test directory " + self.options.tmpdir) + initialize_chain(self.options.tmpdir) + + def setup_network(self, split=False): + self.nodes = start_nodes(2, self.options.tmpdir) + connect_nodes_bi(self.nodes, 0, 1) + self.is_network_split = False + self.sync_all() + + def run_test(self): + self._test_gettxoutsetinfo() + self._test_getblockheader() + self.nodes[0].verifychain(4, 0) + + def _test_gettxoutsetinfo(self): + node = self.nodes[0] + res = node.gettxoutsetinfo() + + assert_equal(res['total_amount'], Decimal('8725.00000000')) + assert_equal(res['transactions'], 200) + assert_equal(res['height'], 200) + assert_equal(res['txouts'], 200) + size = res["disk_size"] + assert (size > 6400) + assert (size < 64000) + assert_equal(res['bestblock'], node.getblockhash(200)) + assert_equal(len(res['bestblock']), 64) + assert_equal(len(res['hash_serialized_2']), 64) + + print ("Test that gettxoutsetinfo() works for blockchain with just the genesis block") + b1hash = node.getblockhash(1) + node.invalidateblock(b1hash) + + res2 = node.gettxoutsetinfo() + assert_equal(res2['transactions'], 0) + assert_equal(res2['total_amount'], Decimal('0')) + assert_equal(res2['height'], 0) + assert_equal(res2['txouts'], 0) + assert_equal(res2['bestblock'], node.getblockhash(0)) + assert_equal(len(res2['hash_serialized_2']), 64) + + print ("Test that gettxoutsetinfo() returns the same result after invalidate/reconsider block") + node.reconsiderblock(b1hash) + + res3 = node.gettxoutsetinfo() + assert_equal(res['total_amount'], res3['total_amount']) + assert_equal(res['transactions'], res3['transactions']) + assert_equal(res['height'], res3['height']) + assert_equal(res['txouts'], res3['txouts']) + assert_equal(res['bestblock'], res3['bestblock']) + assert_equal(res['hash_serialized_2'], res3['hash_serialized_2']) + + def _test_getblockheader(self): + node = self.nodes[0] + + assert_raises( + JSONRPCException, lambda: node.getblockheader('nonsense')) + + besthash = node.getbestblockhash() + secondbesthash = node.getblockhash(199) + header = node.getblockheader(besthash) + + assert_equal(header['hash'], besthash) + assert_equal(header['height'], 200) + assert_equal(header['confirmations'], 1) + assert_equal(header['previousblockhash'], secondbesthash) + assert_is_hex_string(header['chainwork']) + assert_is_hash_string(header['hash']) + assert_is_hash_string(header['previousblockhash']) + assert_is_hash_string(header['merkleroot']) + assert_is_hash_string(header['bits'], length=None) + assert isinstance(header['time'], int) + assert isinstance(header['mediantime'], int) + assert isinstance(header['nonce'], int) + assert isinstance(header['version'], int) + assert isinstance(int(header['versionHex'], 16), int) + assert isinstance(header['difficulty'], Decimal) + +if __name__ == '__main__': + BlockchainTest().main() diff --git a/qa/rpc-tests/buip055.py b/qa/rpc-tests/buip055.py new file mode 100644 index 00000000..73211704 --- /dev/null +++ b/qa/rpc-tests/buip055.py @@ -0,0 +1,631 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import time +import shutil +import random +from binascii import hexlify +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal +from test_framework.util import * +from test_framework.script import * +from test_framework.blocktools import * +from test_framework.bunode import * +import test_framework.script as script +import traceback +import pdb +import sys +if sys.version_info[0] < 3: + raise "Use Python 3" +import logging +logging.basicConfig(format='%(asctime)s.%(levelname)s: %(message)s', level=logging.INFO, stream=sys.stdout) + +NODE_BITCOIN_CASH = (1 << 5) +invalidOpReturn = hexlify(b'Bitcoin: A Peer-to-Peer Electronic Cash System') + +def bitcoinAddress2bin(btcAddress): + """convert a bitcoin address to binary data capable of being put in a CScript""" + # chop the version and checksum out of the bytes of the address + return decodeBase58(btcAddress)[1:-4] + + +B58_DIGITS = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' + + +def decodeBase58(s): + """Decode a base58-encoding string, returning bytes""" + if not s: + return b'' + + # Convert the string to an integer + n = 0 + for c in s: + n *= 58 + if c not in B58_DIGITS: + raise InvalidBase58Error('Character %r is not a valid base58 character' % c) + digit = B58_DIGITS.index(c) + n += digit + + # Convert the integer to bytes + h = '%x' % n + if len(h) % 2: + h = '0' + h + res = binascii.unhexlify(h.encode('utf8')) + + # Add padding back. + pad = 0 + for c in s[:-1]: + if c == B58_DIGITS[0]: + pad += 1 + else: + break + return b'\x00' * pad + res + + +def wastefulOutput(btcAddress): + """ Warning: Creates outputs that can't be spent by bitcoind""" + data = b"""this is junk data. this is junk data. this is junk data. this is junk data. this is junk data. +this is junk data. this is junk data. this is junk data. this is junk data. this is junk data. +this is junk data. this is junk data. this is junk data. this is junk data. this is junk data.""" + ret = CScript([data, OP_DROP, OP_DUP, OP_HASH160, bitcoinAddress2bin(btcAddress), OP_EQUALVERIFY, OP_CHECKSIG]) + return ret + + +def p2pkh(btcAddress): + """ create a pay-to-public-key-hash script""" + ret = CScript([OP_DUP, OP_HASH160, bitcoinAddress2bin(btcAddress), OP_EQUALVERIFY, OP_CHECKSIG]) + return ret + + +def createrawtransaction(inputs, outputs, outScriptGenerator=p2pkh): + """ + Create a transaction with the exact input and output syntax as the bitcoin-cli "createrawtransaction" command. + If you use the default outScriptGenerator, this function will return a hex string that exactly matches the + output of bitcoin-cli createrawtransaction. + """ + if not type(inputs) is list: + inputs = [inputs] + + tx = CTransaction() + for i in inputs: + tx.vin.append(CTxIn(COutPoint(i["txid"], i["vout"]), b"", 0xffffffff)) + for addr, amount in outputs.items(): + if addr == "data": + tx.vout.append(CTxOut(0, CScript([OP_RETURN, unhexlify(amount)]))) + else: + tx.vout.append(CTxOut(amount * BTC, outScriptGenerator(addr))) + tx.rehash() + return hexlify(tx.serialize()).decode("utf-8") + + +def mostly_sync_mempools(rpc_connections, difference=50, wait=1,verbose=1): + """ + Wait until everybody has the most of the same transactions in their memory + pools. There is no guarantee that mempools will ever sync due to the + filterInventoryKnown bloom filter. + """ + iterations = 0 + while True: + iterations+=1 + pool = set(rpc_connections[0].getrawmempool()) + num_match = 1 + poolLen = [len(pool)] + for i in range(1, len(rpc_connections)): + tmp = set(rpc_connections[i].getrawmempool()) + if tmp == pool: + num_match = num_match+1 + if iterations > 10 and len(tmp.symmetric_difference(pool)) < difference: + num_match = num_match+1 + poolLen.append(len(tmp)) + if verbose: + logging.info("sync mempool: " + str(poolLen)) + if num_match == len(rpc_connections): + break + time.sleep(wait) + + +class BUIP055Test (BitcoinTestFramework): + def __init__(self, extended=False): + self.extended = extended + BitcoinTestFramework.__init__(self) + + def setup_network(self, split=False): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-rpcservertimeout=0"], timewait=60 * 10)) + self.nodes.append(start_node(1, self.options.tmpdir, ["-rpcservertimeout=0"], timewait=60 * 10)) + self.nodes.append(start_node(2, self.options.tmpdir, ["-rpcservertimeout=0"], timewait=60 * 10)) + self.nodes.append(start_node(3, self.options.tmpdir, ["-rpcservertimeout=0"], timewait=60 * 10)) + interconnect_nodes(self.nodes) + self.is_network_split = False + self.sync_all() + + def testDefaults(self): + for n in self.nodes: + nodeInfo = n.getnetworkinfo() + t = n.get("mining.fork*") + assert(t['mining.forkBlockSize'] == 2000000) # REQ-4-2 + assert(t['mining.forkExcessiveBlock'] == 8000000) # REQ-4-1 + + if int(nodeInfo["localservices"],16)&NODE_BITCOIN_CASH: + assert(t['mining.forkTime'] == 1501590000) # Bitcoin Cash release REQ-2 + else: + assert(t['mining.forkTime'] == 0) # main release default + + def testCli(self): + n = self.nodes[0] + now = int(time.time()) + n.set("mining.forkTime=%d" % now) + n.set("mining.forkExcessiveBlock=9000000") + n.set("mining.forkBlockSize=3000000") + n = self.nodes[1] + n.set("mining.forkTime=%d" % now, "mining.forkExcessiveBlock=9000000", "mining.forkBlockSize=3000000") + + # Verify that the values were properly set + for n in self.nodes[0:2]: + t = n.get("mining.fork*") + assert(t['mining.forkBlockSize'] == 3000000) + assert(t['mining.forkExcessiveBlock'] == 9000000) + assert(t['mining.forkTime'] == now) + + self.nodes[3].set("mining.forkTime=0") + nodeInfo = self.nodes[3].getnetworkinfo() + + # if this is a bitcoin cash build, we need to do the cash defaults on our old chain node + if int(nodeInfo["localservices"],16)&NODE_BITCOIN_CASH: + self.nodes[3].set("net.excessiveBlock=1000000") # keep it on the 1MB chain + self.nodes[3].set("net.onlyRelayForkSig=False") + self.nodes[2].set("net.excessiveBlock=1000000") # keep it on the 1MB chain + self.nodes[2].set("net.onlyRelayForkSig=False") + + return now + + def createUtxos(self, node, addrs, amt): + wallet = node.listunspent() + wallet.sort(key=lambda x: x["amount"], reverse=True) + + # Create a LOT of UTXOs + logging.info("Create lots of UTXOs...") + n = 0 + group = min(100, amt) + count = 0 + for w in wallet: + count += group + split_transaction(node, [w], addrs[n:group + n]) + n += group + if n >= len(addrs): + n = 0 + if count > amt: + break + logging.info("mine blocks") + node.generate(1) # mine all the created transactions + logging.info("sync all blocks and mempools") + self.sync_all() + + def generateTx(self, node, txBytes, addrs, data=None): + wallet = node.listunspent() + wallet.sort(key=lambda x: x["amount"], reverse=False) + logging.info("Wallet length is %d" % len(wallet)) + + size = 0 + count = 0 + decContext = decimal.getcontext().prec + decimal.getcontext().prec = 8 + 8 # 8 digits to get to 21million, and each bitcoin is 100 million satoshis + while size < txBytes: + count += 1 + utxo = wallet.pop() + outp = {} + # Make the tx bigger by adding addtl outputs so it validates faster + payamt = satoshi_round(utxo["amount"] / decimal.Decimal(8.0)) + for x in range(0, 8): + # its test code, I don't care if rounding error is folded into the fee + outp[addrs[(count + x) % len(addrs)]] = payamt + #outscript = self.wastefulOutput(addrs[(count+x)%len(addrs)]) + #outscripthex = hexlify(outscript).decode("ascii") + #outp[outscripthex] = payamt + if data: + outp["data"] = data + txn = createrawtransaction([utxo], outp, wastefulOutput) + # txn2 = node.createrawtransaction([utxo], outp) + signedtxn = node.signrawtransaction(txn) + size += len(binascii.unhexlify(signedtxn["hex"])) + node.sendrawtransaction(signedtxn["hex"]) + logging.info("%d tx %d length" % (count, size)) + decimal.getcontext().prec = decContext + return (count, size) + + def testNetMagic(self): + info = self.nodes[0].getnetworkinfo() + + # Both BUcash and BU should connect to a normal BU node + bunode = BasicBUNode() + bunode.connect(0,'127.0.0.1', p2p_port(1), self.nodes[1]) + NetworkThread().start() # Start up network handling in another thread + bunode.cnxns[0].wait_for_verack() + + buCashNode = BasicBUCashNode() + buCashNode.connect(0,'127.0.0.1', p2p_port(0), self.nodes[0]) + if int(info["localservices"],16)&NODE_BITCOIN_CASH: + try: # Accept BU cash nodes if running BTC node + buCashNode.cnxns[0].wait_for_buverack() + except DisconnectedError: + assert(not "should not have disconnected a bitcoin cash node") + else: + try: # do not accept BU cash nodes if running BTC node + buCashNode.cnxns[0].wait_for_buverack() + assert(not "should have disconnected a bitcoin cash node") + except DisconnectedError: + logging.info("properly disconnected bucash node") + + def run_test(self): + # this test is mean to test fork scenarios starting from mainchain nodes. + nodeInfo = self.nodes[0].getnetworkinfo() + if int(nodeInfo["localservices"],16)&NODE_BITCOIN_CASH: + return + + # Creating UTXOs needed for building tx for large blocks + self.testNetMagic() + NUM_ADDRS = 50 + logging.info("Creating addresses...") + self.nodes[0].keypoolrefill(NUM_ADDRS) + self.nodes[1].keypoolrefill(NUM_ADDRS) + addrs = [self.nodes[0].getnewaddress() for _ in range(NUM_ADDRS)] + addrs1 = [self.nodes[1].getnewaddress() for _ in range(NUM_ADDRS)] + addrs3 = [self.nodes[3].getnewaddress() for _ in range(5)] + logging.info("creating utxos") + + self.nodes[1].generate(5) + sync_blocks(self.nodes) + + self.createUtxos(self.nodes[0], addrs, 3000) + for i in range(0,2): + self.createUtxos(self.nodes[1], addrs1, 3000) + self.createUtxos(self.nodes[3], addrs3, 3000) + + sync_blocks(self.nodes) + + self.testDefaults() + time.sleep(1) # by controlling the forkTime, we know exactly what the median block will be + forkTime = self.testCli() # also sets up parameters on nodes 0, 1 to to fork + time.sleep(2) # Wait to ensure that every newly generated block is after the fork time. + + base = [x.getblockcount() for x in self.nodes] + assert_equal(base, [base[0]] * 4) + + # TEST REQ-3: that a <= 1 MB block is rejected by the fork nodes + # the rejection happens for the block after the block whose median time of the prior + # 11 blocks is >= the fork time. This is tricky to test exactly because we cannot + # control a block's nTime from this python code. + + # If I generate lots of blocks at once, via generate(15) it is possible that + # the small block fork nodes will disconnect from the large block nodes before + # fully syncing because they get the invalid fork block. + # This won't happen in mainnet because blocks aren't solved instantly and because + # other fork nodes will relay the blocks. + for i in range(0,15): + self.nodes[3].generate(1) + time.sleep(2) + + sync_blocks(self.nodes[2:]) + sync_blocks(self.nodes[0:2]) + + nMedianTimeSpan = 11 # from chain.h + projectedForkHeight = int(base[0] + nMedianTimeSpan / 2 + 1) + + counts = [x.getblockcount() for x in self.nodes] + logging.info("waiting for block: %d" % projectedForkHeight) + while counts[0] != projectedForkHeight: + counts = [x.getblockcount() for x in self.nodes] + logging.info(counts) + time.sleep(1) + + assert(counts[0] < counts[2]) + assert(counts[1] < counts[3]) + assert(counts[0] == counts[1]) + assert(counts[2] == counts[3]) + + # TEST that the client refuses to make a < 1MB fork block + node = self.nodes[0] + + try: + ret = node.generate(1) + logging.info(ret) + assert(0) # should have raised exception + except JSONRPCException as e: + assert("bad-blk-too-small" in e.error["message"]) + + logging.info("Building > 1MB block...") + + # TEST that the client refuses to include invalid op return txns in the first block + self.generateTx(node, 950000, addrs, data='54686973206973203830206279746573206f6620746573742064617461206372656174656420746f20757365207570207472616e73616374696f6e20737061636520666173746572202e2e2e2e2e2e2e') + try: + self.generateTx(node,100000, addrs,data=invalidOpReturn) + assert(0) # should have raised exception + except JSONRPCException as e: + assert("wrong-fork" in e.error["message"]) + + # temporarily turn off forking so we can inject some bad tx into the mempool + node.set("mining.forkTime=0") + unspendableTx, unspendableTxSize = self.generateTx(node,100000, addrs,data=invalidOpReturn) + node.set("mining.forkTime=%d" % forkTime) + + # node 3 is not forking so these tx are allowed + self.generateTx(self.nodes[3],100000,addrs,data=invalidOpReturn) + + try: + ret = node.generate(1) + logging.info(ret) + assert(0) # should have raised exception + except JSONRPCException as e: + assert("bad-blk-too-small" in e.error["message"]) + logging.info("PASS: Invalid OP return transactions were not used when attempting to make the fork block") + + # TEST REQ-3: generate a large block + self.generateTx(node, 100000, addrs) + # if we don't sync mempools, when a block is created the system will be so busy syncing tx that it will time out + # requesting the block, and so never receive it. + # This only happens in testnet because there is only 1 node generating all the tx and with the block. + # But node 0 has a lot of invalid transactions in it, so the sync needs to be pretty loose + mostly_sync_mempools(self.nodes[0:2],difference=100, wait=2) + + commonAncestor = node.getbestblockhash() + node.generate(1) + forkHeight = node.getblockcount() + print("forkHeight: %d" % forkHeight) + # Test that the forked nodes accept this block as the fork block + sync_blocks(self.nodes[0:2]) + # counts = [ x.getblockcount() for x in self.nodes[0:2] ] + counts = [x.getblockcount() for x in self.nodes] + logging.info(counts) + + # generate blocks and ensure that the other node syncs them + self.nodes[1].generate(1) + wallet = self.nodes[1].listunspent() + utxo = wallet.pop() + txn = createrawtransaction([utxo], {addrs1[0]:utxo["amount"]}, wastefulOutput) + signedtxn = self.nodes[1].signrawtransaction(txn,None,None, "ALL|NOFORKID") + signedtxn2 = self.nodes[1].signrawtransaction(txn,None,None,"ALL|FORKID") + assert(signedtxn["hex"] != signedtxn2["hex"]) # they should use a different sighash method + try: + self.nodes[3].sendrawtransaction(signedtxn2["hex"]) + except JSONRPCException as e: + assert("mandatory-script-verify-flag-failed" in e.error["message"]) + logging.info("PASS: New sighash rejected from 1MB chain") + self.nodes[1].sendrawtransaction(signedtxn2["hex"]) + try: + self.nodes[1].sendrawtransaction(signedtxn["hex"]) + except JSONRPCException as e: + assert("txn-mempool-conflict" in e.error["message"]) + logging.info("PASS: submission of new and old sighash txn rejected") + self.nodes[1].generate(1) + + # connect 1 to 3 to propagate these transactions + connect_nodes(self.nodes[1],3) + + # Issue sendtoaddress commands using both the new sighash and the old and ensure that first fails, second works. + self.nodes[1].set("wallet.useNewSig=False") + try: + txhash2 = self.nodes[1].sendtoaddress(addrs[0], 2.345) + assert( not "fork must use new sighash") + except JSONRPCException as e: + txhash2 = self.nodes[3].sendtoaddress(addrs[0], 2.345) + + self.nodes[1].set("wallet.useNewSig=True") + # produce a new sighash transaction using the sendtoaddress API + txhash = self.nodes[1].sendtoaddress(addrs[0], 1.234) + rawtx = self.nodes[1].getrawtransaction(txhash) + try: + self.nodes[3].sendrawtransaction(rawtx) + print("ERROR!") # error assert(0) + except JSONRPCException as e: + assert("mandatory-script-verify-flag-failed" in e.error["message"]) + # hitting this exception verifies that the new format was rejected by the unforked node and that the new format was generated + + #rawtx = self.nodes[1].getrawtransaction(txhash2) + #self.nodes[3].sendrawtransaction(rawtx) # should replay on the small block fork, since its an old sighash tx + + self.nodes[1].generate(1) + txinfo = self.nodes[1].gettransaction(txhash) + assert(txinfo["blockindex"] > 0) # ensure that the new-style tx was included in the block + try: + txinfo = self.nodes[1].gettransaction(txhash2) + assert(not "old transaction was improperly accepted in forked node") + except JSONRPCException: + pass + + #if self.nodes[1].get("net.onlyRelayForkSig")["net.onlyRelayForkSig"]: + # assert(not "blockindex" in txinfo) # old style won't be included in the block + #else: + # assert(txinfo["blockindex"] > 0) # ensure that the old-style tx was included in the block + + # small block node should have gotten this cross-chain replayable tx + txsIn3 = self.nodes[3].getrawmempool() + assert(txhash2 in txsIn3) + self.nodes[3].generate(1) + txsIn3 = self.nodes[3].getrawmempool() + assert(txsIn3 == []) # all transactions were included in the block + + # Issue sendmany commands using both the new sighash and the ond and ensure that they work. + try: + self.nodes[1].set("wallet.useNewSig=False") + txhash2 = self.nodes[1].sendmany("",{addrs[0]:2.345, addrs[1]:1.23}) + assert(not "this tx should not have been accepted") + except JSONRPCException: + pass + self.nodes[1].set("wallet.useNewSig=True") + # produce a new sighash transaction using the sendtoaddress API + txhash = self.nodes[1].sendmany("",{addrs[0]:0.345, addrs[1]:0.23}) + rawtx = self.nodes[1].getrawtransaction(txhash) + try: + self.nodes[3].sendrawtransaction(rawtx) + print("ERROR!") # error assert(0) + except JSONRPCException as e: + assert("mandatory-script-verify-flag-failed" in e.error["message"]) + # hitting this exception verifies that the new format was rejected by the unforked node and that the new format was generated + self.nodes[1].generate(1) + + sync_blocks(self.nodes[0:2]) + + self.nodes[0].generate(2) + sync_blocks(self.nodes[0:2]) + + # generate blocks on the original side + sync_blocks(self.nodes[2:]) + hashes = self.nodes[2].generate(2) + print(hashes) + sync_blocks(self.nodes[2:]) + counts = [x.getblockcount() for x in self.nodes] + assert(counts == [forkHeight + 6, forkHeight + 6, base[3] + 15 + 3, base[3] + 15 + 3]) + forkBest = self.nodes[0].getbestblockhash() + origBest = self.nodes[3].getbestblockhash() + logging.info("Fork height: %d" % forkHeight) + logging.info("Common ancestor: %s" % commonAncestor) + logging.info("Fork tip: %s" % forkBest) + logging.info("Small block tip: %s" % origBest) + + # Limitation: fork logic will not cause a re-org if the node is beyond it + logging.info("Show that a re-org will not happen if the stopped/started node is already beyond the fork") + stop_node(self.nodes[2], 2) + self.nodes[2] = start_node(2, self.options.tmpdir, ["-debug", "-mining.forkTime=%d" % + forkTime, "-mining.forkExcessiveBlock=9000000", "-mining.forkBlockSize=3000000"], timewait=900) + connect_nodes(self.nodes[2], 3) + connect_nodes(self.nodes[2], 0) + sync_blocks(self.nodes[0:2]) + assert(self.nodes[2].getbestblockhash() == origBest) + + # Now clean up the node to force a re-sync, but connect to the small block fork nodes + logging.info("Resync but only connected to the small block nodes") + stop_node(self.nodes[2], 2) + shutil.rmtree(self.options.tmpdir + os.sep + "node2" + os.sep + "regtest") + self.nodes[2] = start_node(2, self.options.tmpdir, ["-debug", "-mining.forkTime=%d" % + forkTime, "-mining.forkExcessiveBlock=9000000", "-mining.forkBlockSize=3000000"], timewait=900) + connect_nodes(self.nodes[2], 3) + + # I'm not expecting the nodes to fully sync because the fork client is only connected to the small block clients + waitCount = 0 + while self.nodes[2].getblockcount() < forkHeight - 1: + time.sleep(5) + waitCount += 5 + if waitCount > 30: + # we can't be sure the node will fully sync. It may be dropped early + logging.info("Node did not sync up to the fork height") + break + logging.info(self.nodes[2].getblockcount()) + if self.nodes[2].getpeerinfo() == []: # I'll drop as soon as peer 3 tries to give me the invalid fork block + break + time.sleep(10) # wait longer to see if we continue to sync + t = self.nodes[2].getinfo() + + # Cannot progress beyond the common ancestor, because we are looking for a big block + # however, if we were processing multiple blocks at once, we might not get to exactly forkHeight - 1 so < is needed + assert(t["blocks"] < forkHeight) + + # now connect to fork node to see it continue to sync + logging.info("connect to a large block node and see that sync completes") + self.nodes[0].clearbanned() # node 2 can get banned in prior tests because it may have served the small block + connect_nodes(self.nodes[2], 0) + sync_blocks(self.nodes[0:3]) + assert(self.nodes[2].getbestblockhash() == forkBest) + + # test full sync if only connected to forked nodes + stop_node(self.nodes[2], 2) + logging.info("Resync to minority fork connected to minority fork nodes only") + + shutil.rmtree(self.options.tmpdir + os.sep + "node2" + os.sep + "regtest") + self.nodes[2] = start_node(2, self.options.tmpdir, ["-debug", "-mining.forkTime=%d" % + forkTime, "-mining.forkExcessiveBlock=9000000", "-mining.forkBlockSize=3000000"], timewait=900) + self.nodes[0].clearbanned() # node 2 can get banned in prior tests because it may have served the small block + connect_nodes(self.nodes[2], 0) + sync_blocks(self.nodes[0:3]) + t = self.nodes[2].getinfo() + assert(self.nodes[2].getbestblockhash() == forkBest) + + # Now clean up the node to force a re-sync, but connect to both forks to prove it follows the proper fork + stop_node(self.nodes[2], 2) + logging.info("Resync to minority fork in the presence of majority fork nodes") + shutil.rmtree(self.options.tmpdir + os.sep + "node2" + os.sep + "regtest") + self.nodes[2] = start_node(2, self.options.tmpdir, ["-debug", "-mining.forkTime=%d" % + forkTime, "-mining.forkExcessiveBlock=9000000", "-mining.forkBlockSize=3000000"], timewait=900) + self.nodes[0].clearbanned() # node 2 can get banned in prior tests because it may have served the small block + self.nodes[3].clearbanned() # node 2 can get banned in prior tests because it may have served the small block + connect_nodes(self.nodes[2], 3) + connect_nodes(self.nodes[2], 0) + sync_blocks(self.nodes[0:3]) + + assert(self.nodes[2].getbestblockhash() == forkBest) + # pdb.set_trace() + + logging.info("Reindex across fork") + # see if we reindex properly across the fork + node = self.nodes[2] + curCount = node.getblockcount() + stop_node(node, 2) + node = self.nodes[2] = start_node(2, self.options.tmpdir, ["-debug", "-reindex", "-checkblockindex=1", "-mining.forkTime=%d" % + forkTime, "-mining.forkExcessiveBlock=9000000", "-mining.forkBlockSize=3000000"], timewait=900) + time.sleep(10) + assert_equal(node.getblockcount(), curCount) + + connect_nodes(self.nodes[2], 3) + connect_nodes(self.nodes[2], 0) + + # Verify that the unspendable tx I created never got spent + mempool = self.nodes[0].getmempoolinfo() + print(mempool) + print(unspendableTx) + leftOverTx = mempool["size"] - unspendableTx + assert(leftOverTx >= 0) # + a few old chain tx which is why > or = + + # Now create some big blocks to ensure that we are properly creating them + self.generateTx(self.nodes[1], 1005000, addrs, data='54686973206973203830206279746573206f6620746573742064617461206372656174656420746f20757365207570207472616e73616374696f6e20737061636520666173746572202e2e2e2e2e2e2e') + blkHash = self.nodes[1].generate(1)[0] + blkInfo = self.nodes[1].getblock(blkHash) + assert(blkInfo["size"] > 1000000) + self.generateTx(self.nodes[1], 4000000, addrs, data='54686973206973203830206279746573206f6620746573742064617461206372656174656420746f20757365207570207472616e73616374696f6e20737061636520666173746572202e2e2e2e2e2e2e') + blkHash = self.nodes[1].generate(1)[0] + blkInfo = self.nodes[1].getblock(blkHash) + assert(blkInfo["size"] <= 3000000) # this is the configured max block size for this test + assert(blkInfo["size"] >= 2900000) # block should have been filled up! + + self.nodes[1].generate(1) # should consume all the rest of the spendable tx + + # The unspendable tx I created on node 0 should not have been relayed to node 1 + mempool = self.nodes[1].getmempoolinfo() + assert(mempool["size"] >= leftOverTx) + + sync_blocks(self.nodes[0:3]) + # The unspendable tx I created on node 0 should still be there + mempool = self.nodes[0].getmempoolinfo() + assert(mempool["size"] >= leftOverTx) + + +def info(type, value, tb): + if hasattr(sys, 'ps1') or not sys.stderr.isatty(): + # we are in interactive mode or we don't have a tty-like + # device, so we call the default hook + sys.__excepthook__(type, value, tb) + else: + import traceback + import pdb + # we are NOT in interactive mode, print the exception... + traceback.print_exception(type, value, tb) + print + # ...then start the debugger in post-mortem mode. + pdb.pm() + + +sys.excepthook = info + + +def Test(): + t = BUIP055Test(True) + t.drop_to_pdb = True + bitcoinConf = { + "debug": ["net", "blk", "thin", "mempool", "req", "bench", "evict"], # "lck" + "blockprioritysize": 2000000 # we don't want any transactions rejected due to insufficient fees... + } + t.main(["--tmpdir=/ramdisk/test","--nocleanup","--noshutdown"], bitcoinConf, None) # , "--tracerpc"]) + + +if __name__ == '__main__': + BUIP055Test(True).main(sys.argv) diff --git a/qa/rpc-tests/bunode.py b/qa/rpc-tests/bunode.py new file mode 100644 index 00000000..53c764ee --- /dev/null +++ b/qa/rpc-tests/bunode.py @@ -0,0 +1,379 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017 The Bitcoin Unlimited developers +# Copyright (c) 2014-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. + +# wait for py3.6: from enum import Enum,Flag + +from test_framework.mininode import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.blocktools import create_block, create_coinbase + +EXPEDITED_VERSION = 80002 + +# class InvResp(Flags): +REQ_TX = 1 +REQ_THINBLOCK = 2 +REQ_XTHINBLOCK = 4 +REQ_BLOCK = 8 + + +class BUProtocolHandler(NodeConnCB): + def __init__(self): + NodeConnCB.__init__(self) + self.connection = None + self.last_inv = [] + self.last_headers = None + self.last_block = None + self.ping_counter = 1 + self.last_pong = msg_pong(0) + self.last_getdata = [] + self.sleep_time = 0.05 + self.block_announced = False + self.last_getheaders = None + self.disconnected = False + self.remoteVersion = 0 + self.buverack_received = False + self.parent = None + self.requestOnInv = 0 + + def show_debug_msg(self, msg): + print(msg) + + # Spin until verack message is received from the node. + # Tests may want to use this as a signal that the test can begin. + # This can be called from the testing thread, so it needs to acquire the + # global lock. + def wait_for_buverack(self): + while True: + with mininode_lock: + if self.buverack_received: + return + time.sleep(0.05) + + def clear_last_announcement(self): + with mininode_lock: + self.block_announced = False + self.last_inv = [] + self.last_headers = None + + def on_version(self, conn, message): + if message.nVersion >= 209: + conn.send_message(msg_verack()) + conn.ver_send = min(MY_VERSION, message.nVersion) + if message.nVersion < 209: + conn.ver_recv = conn.ver_send + self.remoteVersion = message.nVersion + + def on_verack(self, conn, message): + conn.ver_recv = conn.ver_send + self.verack_received = True + if self.remoteVersion >= EXPEDITED_VERSION: + msg = msg_buversion(conn.socket.getsockname()[1]) + self.connection.send_message(msg) + + def on_buverack(self, conn, message): + self.show_debug_msg("BU version ACK\n") + self.buverack_received = True + + def add_connection(self, conn): + self.connection = conn + + def add_parent(self, p): + self.parent = p + + # Request data for a list of block hashes + def get_data(self, block_hashes): + msg = msg_getdata() + for x in block_hashes: + msg.inv.append(CInv(2, x)) + self.connection.send_message(msg) + + def get_headers(self, locator, hashstop): + msg = msg_getheaders() + msg.locator.vHave = locator + msg.hashstop = hashstop + self.connection.send_message(msg) + + def send_block_inv(self, blockhash): + msg = msg_inv() + msg.inv = [CInv(2, blockhash)] + self.connection.send_message(msg) + + # Wrapper for the NodeConn's send_message function + def send_message(self, message): + self.connection.send_message(message) + + def on_inv(self, conn, message): + self.last_inv.append(message) + self.block_announced = True + for inv in message.inv: + if inv.type == CInv.MSG_BLOCK: + if self.requestOnInv & REQ_BLOCK: + msg = msg_getdata(inv) + self.send_message(msg) + self.show_debug_msg("requested block") + if self.requestOnInv & REQ_THINBLOCK: + msg = msg_getdata(CInv(CInv.MSG_THINBLOCK, inv.hash)) + self.send_message(msg) + self.show_debug_msg("requested thinblock") + if self.requestOnInv & REQ_XTHINBLOCK: + msg = msg_getdata(CInv(CInv.MSG_XTHINBLOCK, inv.hash)) + self.send_message(msg) + self.show_debug_msg("requested xtinblock") + + def on_headers(self, conn, message): + self.last_headers = message + self.block_announced = True + + def on_block(self, conn, message): + self.last_block = message.block + self.last_block.calc_sha256() + if self.parent and hasattr(self.parent, "on_block"): + self.parent.on_block(self, message) + + def on_thinblock(self, conn, message): + self.last_block = message.block + self.last_block.calc_sha256() + if self.parent and hasattr(self.parent, "on_thinblock"): + self.parent.on_thinblock(self, message) + + def on_xthinblock(self, conn, message): + self.last_block = message.block + self.last_block.calc_sha256() + if self.parent and hasattr(self.parent, "on_xthinblock"): + self.parent.on_xthinblock(self, message) + + def on_getdata(self, conn, message): + self.last_getdata.append(message) + + def on_pong(self, conn, message): + self.last_pong = message + + def on_getheaders(self, conn, message): + self.last_getheaders = message + + def on_close(self, conn): + self.disconnected = True + + # Test whether the last announcement we received had the + # right header or the right inv + # inv and headers should be lists of block hashes + def check_last_announcement(self, headers=None, inv=[]): + expect_headers = headers if headers != None else [] + expect_inv = inv if inv != [] else [] + + def test_function(): return self.block_announced + self.sync(test_function) + timeout = 5 + while timeout > 0: + with mininode_lock: + self.block_announced = False + + success = True + compare_inv = [] + if self.last_inv != []: + all_inv = [x.inv for x in self.last_inv] + for x in all_inv: + test_inv = [y.hash for y in x] + compare_inv = compare_inv + test_inv + + # Check whether the inventory received is within the list of block hashes that were + # mined (During a large reorg the inv's will be fewer than the actual hashes mined). + s = set(compare_inv) + expect_inv = [x for x in expect_inv if x in s] + if compare_inv != expect_inv: + success = False + + hash_headers = [] + if self.last_headers != None: + # treat headers as a list of block hashes + hash_headers = [x.sha256 for x in self.last_headers.headers] + if hash_headers != expect_headers: + success = False + + self.last_inv = [] + self.last_headers = None + + if success == True: + return success + + time.sleep(self.sleep_time) + timeout -= self.sleep_time + + # Syncing helpers + def sync(self, test_function, timeout=60): + while timeout > 0: + with mininode_lock: + if test_function(): + return + + time.sleep(self.sleep_time) + timeout -= self.sleep_time + raise AssertionError("Sync failed to complete") + + # The request manager does not deal with vectors of GETDATA requests but rather one GETDATA per + # hash, therefore we need to be able to sync_getdata one message at a time rather than in batches. + def sync_getdata(self, hash_list, timeout=60): + while timeout > 0: + with mininode_lock: + # Check whether any getdata responses are in the hash list and + # if so remove them from both lists. + for x in self.last_getdata: + for y in hash_list: + if (str(x.inv).find(hex(y)[2:]) > 0): + self.last_getdata.remove(x) + hash_list.remove(y) + if hash_list == []: + return + + time.sleep(self.sleep_time) + timeout -= self.sleep_time + raise AssertionError("Sync getdata failed to complete") + + def sync_with_ping(self, timeout=60): + self.send_message(msg_ping(nonce=self.ping_counter)) + + def test_function(): return self.last_pong.nonce == self.ping_counter + self.sync(test_function, timeout) + self.ping_counter += 1 + return + + def wait_for_block(self, blockhash, timeout=60): + def test_function(): return self.last_block != None and self.last_block.sha256 == blockhash + self.sync(test_function, timeout) + return + + def wait_for_getheaders(self, timeout=60): + def test_function(): return self.last_getheaders != None + self.sync(test_function, timeout) + return + + def wait_for_getdata(self, hash_list, timeout=60): + if hash_list == []: + return + + self.sync_getdata(hash_list, timeout) + return + + def wait_for_disconnect(self, timeout=60): + def test_function(): return self.disconnected + self.sync(test_function, timeout) + return + + def send_header_for_blocks(self, new_blocks): + headers_message = msg_headers() + headers_message.headers = [CBlockHeader(b) for b in new_blocks] + self.send_message(headers_message) + + def send_getblocks(self, locator): + getblocks_message = msg_getblocks() + getblocks_message.locator.vHave = locator + self.send_message(getblocks_message) + + +class BasicBUNode: + def __init__(self): + self.cnxns = {} + self.nblocks = 0 + self.nthin = 0 + self.nxthin = 0 + + def connect(self, id, ip, port, rpc=None, protohandler=None): + if not protohandler: + protohandler = BUProtocolHandler() + conn = NodeConn(ip, port, rpc, protohandler) + protohandler.add_connection(conn) + protohandler.add_parent(self) + self.cnxns[id] = protohandler + + def on_block(self, frm, message): + print("got block") + self.nblocks += 1 + + def on_thinblock(self, frm, message): + print("got thinblock") + self.nthin += 1 + + def on_xthinblock(self, frm, message): + print("got xthinblock") + self.nxthin += 1 + + +class TestClass(BitcoinTestFramework): + + def createUtxos(self, node, addrs, amt): + wallet = node.listunspent() + wallet.sort(key=lambda x: x["amount"], reverse=True) + + # Create a LOT of UTXOs + logging.info("Create lots of UTXOs...") + n = 0 + group = min(100, amt) + count = 0 + for w in wallet: + count += group + split_transaction(node, [w], addrs[n:group + n]) + n += group + if n >= len(addrs): + n = 0 + if count > amt: + break + logging.info("mine blocks") + node.generate(1) # mine all the created transactions + logging.info("sync all blocks and mempools") + + def run_test(self): + # Receive a block of all types + + # I need to create a nontrivial block so thin and xthin saves space. + + # first create addrs + self.nodes[0].keypoolrefill(100) + addrs = [self.nodes[0].getnewaddress() for _ in range(100)] + self.createUtxos(self.nodes[0], addrs, 100) + + # now create the python BU node + pybu = BasicBUNode() + pybu.connect(0, '127.0.0.1', p2p_port(0), self.nodes[0]) + + # set it to request all block types when an INV comes in + pybu.cnxns[0].requestOnInv = REQ_BLOCK | REQ_THINBLOCK | REQ_XTHINBLOCK + + NetworkThread().start() # Start up network handling in another thread + + # Now create a block with lots of tx + node = self.nodes[0] + wallet = node.listunspent() + reverse = copy.copy(wallet) + wallet.sort(key=lambda x: x["amount"], reverse=False) + reverse.sort(key=lambda x: x["amount"], reverse=True) + + try: + for (a, b) in zip(wallet, reverse): + node.sendtoaddress(b["address"], a["amount"]) + except JSONRPCException as e: + pass + + # ok this mined block should make thin & xthin blocks + node.generate(1) + + # Wait for the blocks to come in + while pybu.nblocks == 0 or pybu.nthin == 0 or pybu.nxthin == 0: + time.sleep(.25) + print("received all block types") + + +if __name__ == '__main__': + Test().main() + + +def Test(): + t = TestClass() + bitcoinConf = { + "debug": ["net", "blk", "thin", "mempool", "req", "bench", "evict"], # "lck" + "blockprioritysize": 2000000 # we don't want any transactions rejected due to insufficient fees... + } + t.main(["--tmpdir=/ramdisk/test", "--nocleanup", "--noshutdown"], bitcoinConf, None) # , "--tracerpc"]) diff --git a/qa/rpc-tests/create_cache.py b/qa/rpc-tests/create_cache.py new file mode 100644 index 00000000..1ace6310 --- /dev/null +++ b/qa/rpc-tests/create_cache.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# 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. + +# +# Helper script to create the cache +# (see BitcoinTestFramework.setup_chain) +# + +from test_framework.test_framework import BitcoinTestFramework + +class CreateCache(BitcoinTestFramework): + + def __init__(self): + super().__init__() + + # Test network and test nodes are not required: + self.num_nodes = 0 + self.nodes = [] + + def setup_network(self): + pass + + def run_test(self): + pass + +if __name__ == '__main__': + CreateCache().main() diff --git a/qa/rpc-tests/decodescript.py b/qa/rpc-tests/decodescript.py new file mode 100644 index 00000000..27b30bcc --- /dev/null +++ b/qa/rpc-tests/decodescript.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.mininode import * +from io import BytesIO + +class DecodeScriptTest(BitcoinTestFramework): + """Tests decoding scripts via RPC command "decodescript".""" + + def setup_chain(self): + print('Initializing test directory ' + self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self, split=False): + self.nodes = start_nodes(1, self.options.tmpdir) + self.is_network_split = False + + def decodescript_script_sig(self): + signature = '304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001' + push_signature = '48' + signature + public_key = '03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2' + push_public_key = '21' + public_key + + # below are test cases for all of the standard transaction types + + # 1) P2PK scriptSig + # the scriptSig of a public key scriptPubKey simply pushes a signature onto the stack + rpc_result = self.nodes[0].decodescript(push_signature) + assert_equal(signature, rpc_result['asm']) + + # 2) P2PKH scriptSig + rpc_result = self.nodes[0].decodescript(push_signature + push_public_key) + assert_equal(signature + ' ' + public_key, rpc_result['asm']) + + # 3) multisig scriptSig + # this also tests the leading portion of a P2SH multisig scriptSig + # OP_0 + rpc_result = self.nodes[0].decodescript('00' + push_signature + push_signature) + assert_equal('0 ' + signature + ' ' + signature, rpc_result['asm']) + + # 4) P2SH scriptSig + # an empty P2SH redeemScript is valid and makes for a very simple test case. + # thus, such a spending scriptSig would just need to pass the outer redeemScript + # hash test and leave true on the top of the stack. + rpc_result = self.nodes[0].decodescript('5100') + assert_equal('1 0', rpc_result['asm']) + + # 5) null data scriptSig - no such thing because null data scripts can not be spent. + # thus, no test case for that standard transaction type is here. + + def decodescript_script_pub_key(self): + public_key = '03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2' + push_public_key = '21' + public_key + public_key_hash = '11695b6cd891484c2d49ec5aa738ec2b2f897777' + push_public_key_hash = '14' + public_key_hash + + # below are test cases for all of the standard transaction types + + # 1) P2PK scriptPubKey + # OP_CHECKSIG + rpc_result = self.nodes[0].decodescript(push_public_key + 'ac') + assert_equal(public_key + ' OP_CHECKSIG', rpc_result['asm']) + + # 2) P2PKH scriptPubKey + # OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + rpc_result = self.nodes[0].decodescript('76a9' + push_public_key_hash + '88ac') + assert_equal('OP_DUP OP_HASH160 ' + public_key_hash + ' OP_EQUALVERIFY OP_CHECKSIG', rpc_result['asm']) + + # 3) multisig scriptPubKey + # OP_CHECKMULTISIG + # just imagine that the pub keys used below are different. + # for our purposes here it does not matter that they are the same even though it is unrealistic. + rpc_result = self.nodes[0].decodescript('52' + push_public_key + push_public_key + push_public_key + '53ae') + assert_equal('2 ' + public_key + ' ' + public_key + ' ' + public_key + ' 3 OP_CHECKMULTISIG', rpc_result['asm']) + + # 4) P2SH scriptPubKey + # OP_HASH160 OP_EQUAL. + # push_public_key_hash here should actually be the hash of a redeem script. + # but this works the same for purposes of this test. + rpc_result = self.nodes[0].decodescript('a9' + push_public_key_hash + '87') + assert_equal('OP_HASH160 ' + public_key_hash + ' OP_EQUAL', rpc_result['asm']) + + # 5) null data scriptPubKey + # use a signature look-alike here to make sure that we do not decode random data as a signature. + # this matters if/when signature sighash decoding comes along. + # would want to make sure that no such decoding takes place in this case. + signature_imposter = '48304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001' + # OP_RETURN + rpc_result = self.nodes[0].decodescript('6a' + signature_imposter) + assert_equal('OP_RETURN ' + signature_imposter[2:], rpc_result['asm']) + + # 6) a CLTV redeem script. redeem scripts are in-effect scriptPubKey scripts, so adding a test here. + # OP_NOP2 is also known as OP_CHECKLOCKTIMEVERIFY. + # just imagine that the pub keys used below are different. + # for our purposes here it does not matter that they are the same even though it is unrealistic. + # + # OP_IF + # OP_CHECKSIGVERIFY + # OP_ELSE + # OP_CHECKLOCKTIMEVERIFY OP_DROP + # OP_ENDIF + # OP_CHECKSIG + # + # lock until block 500,000 + rpc_result = self.nodes[0].decodescript('63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac') + assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm']) + + def decoderawtransaction_asm_sighashtype(self): + """Tests decoding scripts via RPC command "decoderawtransaction". + + This test is in with the "decodescript" tests because they are testing the same "asm" script decodes. + """ + + # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output + tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000' + rpc_result = self.nodes[0].decoderawtransaction(tx) + assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm']) + + # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs. + # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc + # verify that we have not altered scriptPubKey decoding. + tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000' + rpc_result = self.nodes[0].decoderawtransaction(tx) + assert_equal('8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid']) + assert_equal('0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm']) + assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) + assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) + txSave = CTransaction() + txSave.deserialize(BytesIO(hex_str_to_bytes(tx))) + + # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type + tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000' + rpc_result = self.nodes[0].decoderawtransaction(tx) + assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm']) + + # verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks + tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000' + rpc_result = self.nodes[0].decoderawtransaction(tx) + assert_equal('OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) + assert_equal('OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) + + # some more full transaction tests of varying specific scriptSigs. used instead of + # tests in decodescript_script_sig because the decodescript RPC is specifically + # for working on scriptPubKeys (argh!). + push_signature = bytes_to_hex_str(txSave.vin[0].scriptSig)[2:(0x48*2+4)] + signature = push_signature[2:] + der_signature = signature[:-2] + signature_sighash_decoded = der_signature + '[ALL]' + signature_2 = der_signature + '82' + push_signature_2 = '48' + signature_2 + signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]' + + # 1) P2PK scriptSig + txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature) + rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize())) + assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) + + # make sure that the sighash decodes come out correctly for a more complex / lesser used case. + txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature_2) + rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize())) + assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) + + # 2) multisig scriptSig + txSave.vin[0].scriptSig = hex_str_to_bytes('00' + push_signature + push_signature_2) + rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize())) + assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) + + # 3) test a scriptSig that contains more than push operations. + # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it. + txSave.vin[0].scriptSig = hex_str_to_bytes('6a143011020701010101010101020601010101010101') + rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize())) + assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm']) + + def run_test(self): + self.decodescript_script_sig() + self.decodescript_script_pub_key() + self.decoderawtransaction_asm_sighashtype() + +if __name__ == '__main__': + DecodeScriptTest().main() diff --git a/qa/rpc-tests/disablewallet.py b/qa/rpc-tests/disablewallet.py new file mode 100644 index 00000000..effe5f59 --- /dev/null +++ b/qa/rpc-tests/disablewallet.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Exercise API with -disablewallet. +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + + +class DisableWalletTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self, split=False): + self.nodes = start_nodes(1, self.options.tmpdir, [['-disablewallet']]) + self.is_network_split = False + self.sync_all() + + def run_test (self): + # Check regression: https://github.com/bitcoin/bitcoin/issues/6963#issuecomment-154548880 + x = self.nodes[0].validateaddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') + assert(x['isvalid'] == False) + 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 as 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 as e: + assert("Invalid address" in e.error['message']) + +if __name__ == '__main__': + DisableWalletTest ().main () diff --git a/qa/rpc-tests/excessive.py b/qa/rpc-tests/excessive.py new file mode 100644 index 00000000..9ec02185 --- /dev/null +++ b/qa/rpc-tests/excessive.py @@ -0,0 +1,709 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# 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. + +# Test emergent consensus scenarios + +import time +import random +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal +from test_framework.util import * +from test_framework.blocktools import * +import test_framework.script as script +import pdb +import sys +if sys.version_info[0] < 3: + raise "Use Python 3" +import logging +logging.basicConfig(format='%(asctime)s.%(levelname)s: %(message)s', level=logging.INFO, stream=sys.stdout) + + +def mostly_sync_mempools(rpc_connections, difference=50, wait=1, verbose=1): + """ + Wait until everybody has the most of the same transactions in their memory + pools. There is no guarantee that mempools will ever sync due to the + filterInventoryKnown bloom filter. + """ + iterations = 0 + while True: + iterations += 1 + pool = set(rpc_connections[0].getrawmempool()) + num_match = 1 + poolLen = [len(pool)] + for i in range(1, len(rpc_connections)): + tmp = set(rpc_connections[i].getrawmempool()) + if tmp == pool: + num_match = num_match + 1 + if iterations > 10 and len(tmp.symmetric_difference(pool)) < difference: + num_match = num_match + 1 + poolLen.append(len(tmp)) + if verbose: + logging.info("sync mempool: " + str(poolLen)) + if num_match == len(rpc_connections): + break + time.sleep(wait) + + +class ExcessiveBlockTest (BitcoinTestFramework): + def __init__(self, extended=False): + self.extended = extended + BitcoinTestFramework.__init__(self) + + def setup_network(self, split=False): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-rpcservertimeout=0"], timewait=60 * 10)) + self.nodes.append(start_node(1, self.options.tmpdir, ["-rpcservertimeout=0"], timewait=60 * 10)) + self.nodes.append(start_node(2, self.options.tmpdir, ["-rpcservertimeout=0"], timewait=60 * 10)) + self.nodes.append(start_node(3, self.options.tmpdir, ["-rpcservertimeout=0"], timewait=60 * 10)) + interconnect_nodes(self.nodes) + self.is_network_split = False + self.sync_all() + + if 0: # getnewaddress can be painfully slow. This bit of code can be used to during development to + # create a wallet with lots of addresses, which then can be used in subsequent runs of the test. + # It is left here for developers to manually enable. + TEST_SIZE = 100 # TMP 00 + print("Creating addresses...") + self.nodes[0].keypoolrefill(TEST_SIZE + 1) + addrs = [self.nodes[0].getnewaddress() for _ in range(TEST_SIZE + 1)] + with open("walletAddrs.json", "w") as f: + f.write(str(addrs)) + pdb.set_trace() + + def run_test(self): + BitcoinTestFramework.run_test(self) + self.testCli() + self.testExcessiveSigops() + + # clear out the mempool + mostly_sync_mempools(self.nodes) + for n in self.nodes: + n.generate(2) + sync_blocks(self.nodes) + for n in self.nodes: + while len(n.getrawmempool()): + n.generate(1) + sync_blocks(self.nodes) + logging.info("cleared mempool: %s" % str([len(x) for x in [y.getrawmempool() for y in self.nodes]])) + self.testExcessiveBlockSize() + self.testExcessiveTx() + + def testCli(self): + + # Assumes the default excessive at 16MB and mining at 1MB + try: + self.nodes[0].setminingmaxblock(32000000) + except JSONRPCException as e: + pass + else: + assert(0) # was able to set the mining size > the excessive size + + try: + self.nodes[0].setminingmaxblock(99) + except JSONRPCException as e: + pass + else: + assert(0) # was able to set the mining size below our arbitrary minimum + + try: + self.nodes[0].setexcessiveblock(1000, 10) + except JSONRPCException as e: + pass + else: + assert(0) # was able to set the excessive size < the mining size + + def sync_all(self): + """Synchronizes blocks and mempools (mempools may never fully sync)""" + if self.is_network_split: + sync_blocks(self.nodes[:2]) + sync_blocks(self.nodes[2:]) + mostly_sync_mempools(self.nodes[:2]) + mostly_sync_mempools(self.nodes[2:]) + else: + sync_blocks(self.nodes) + mostly_sync_mempools(self.nodes) + + def createUtxos(self, node, addrs, amt): + wallet = node.listunspent() + wallet.sort(key=lambda x: x["amount"], reverse=True) + + # Create a LOT of UTXOs + logging.info("Create lots of UTXOs...") + n = 0 + group = min(100, amt) + count = 0 + for w in wallet: + count += group + split_transaction(node, [w], addrs[n:group + n]) + n += group + if n >= len(addrs): + n = 0 + if count > amt: + break + self.sync_all() + logging.info("mine blocks") + node.generate(1) # mine all the created transactions + logging.info("sync all blocks and mempools") + self.sync_all() + + def expectHeights(self, blockHeights, waittime=10): + loop = 0 + count = [] + while loop < waittime: + counts = [x.getblockcount() for x in self.nodes] + if counts == blockHeights: + return True # success! + time.sleep(1) + loop += 1 + if ((loop % 30) == 0): + logging.info("...waiting %s" % loop) + return False + + def generateTx(self, node, txBytes, addrs, data=None): + wallet = node.listunspent() + wallet.sort(key=lambda x: x["amount"], reverse=False) + logging.info("Wallet length is %d" % len(wallet)) + + size = 0 + count = 0 + decContext = decimal.getcontext().prec + decimal.getcontext().prec = 8 + 8 # 8 digits to get to 21million, and each bitcoin is 100 million satoshis + while size < txBytes: + count += 1 + utxo = wallet.pop() + outp = {} + # Make the tx bigger by adding addtl outputs so it validates faster + payamt = satoshi_round(utxo["amount"] / decimal.Decimal(8.0)) + for x in range(0, 8): + # its test code, I don't care if rounding error is folded into the fee + outp[addrs[(count + x) % len(addrs)]] = payamt + #outscript = self.wastefulOutput(addrs[(count+x)%len(addrs)]) + #outscripthex = hexlify(outscript).decode("ascii") + #outp[outscripthex] = payamt + if data: + outp["data"] = data + txn = createrawtransaction([utxo], outp, createWastefulOutput) + # txn2 = node.createrawtransaction([utxo], outp) + signedtxn = node.signrawtransaction(txn) + size += len(binascii.unhexlify(signedtxn["hex"])) + node.sendrawtransaction(signedtxn["hex"]) + logging.info("%d tx %d length" % (count, size)) + decimal.getcontext().prec = decContext + return (count, size) + + def testExcessiveSigops(self): + """This test checks the behavior of the nodes in the presence of transactions that take a long time to validate. + """ + NUM_ADDRS = 100 + logging.info("testExcessiveSigops: Cleaning up node state") + + # We are not testing excessively sized blocks so make these large + self.nodes[0].set("net.excessiveBlock=5000000") + self.nodes[1].set("net.excessiveBlock=5000000") + self.nodes[2].set("net.excessiveBlock=5000000") + self.nodes[3].set("net.excessiveBlock=5000000") + self.nodes[0].setminingmaxblock(5000000) + self.nodes[1].setminingmaxblock(5000000) + self.nodes[2].setminingmaxblock(5000000) + self.nodes[3].setminingmaxblock(5000000) + # Stagger the accept depths so we can see the block accepted stepwise + self.nodes[0].set("net.excessiveAcceptDepth=0") + self.nodes[1].set("net.excessiveAcceptDepth=1") + self.nodes[2].set("net.excessiveAcceptDepth=2") + self.nodes[3].set("net.excessiveAcceptDepth=3") + + for n in self.nodes: + n.generate(10) + self.sync_blocks() + + self.nodes[0].generate(100) # create a lot of BTC for spending + + self.sync_all() + + self.nodes[0].set("net.excessiveSigopsPerMb=100") # Set low so txns will fail if its used + self.nodes[1].set("net.excessiveSigopsPerMb=5000") + self.nodes[2].set("net.excessiveSigopsPerMb=1000") + self.nodes[3].set("net.excessiveSigopsPerMb=100") + + logging.info("Creating addresses...") + self.nodes[0].keypoolrefill(NUM_ADDRS) + addrs = [self.nodes[0].getnewaddress() for _ in range(NUM_ADDRS)] + + # test that a < 1MB block ignores the sigops parameter + self.nodes[0].setminingmaxblock(1000000) + # if excessive Sigops was heeded, this txn would not make it into the block + self.createUtxos(self.nodes[0], addrs, NUM_ADDRS) + mpool = self.nodes[0].getmempoolinfo() + assert_equal(mpool["size"], 0) + + # test that a < 1MB block ignores the sigops parameter, even if the max block size is less + self.nodes[0].setminingmaxblock(5000000) + # if excessive Sigops was heeded, this txn would not make it into the block + self.createUtxos(self.nodes[0], addrs, NUM_ADDRS) + mpool = self.nodes[0].getmempoolinfo() + assert_equal(mpool["size"], 0) + + if self.extended: # creating 1MB+ blocks is too slow for travis due to the signing cost + self.createUtxos(self.nodes[0], addrs, 10000) # we need a lot to generate 1MB+ blocks + + wallet = self.nodes[0].listunspent() + wallet.sort(key=lambda x: x["amount"], reverse=True) + self.nodes[0].set("net.excessiveSigopsPerMb=100000") # Set this huge so all txns are accepted by this node + + logging.info("Generate > 1MB block with excessive sigops") + self.generateTx(self.nodes[0], 1100000, addrs) + + counts = [x.getblockcount() for x in self.nodes] + base = counts[0] + + self.nodes[0].generate(1) + assert_equal(True, self.expectHeights([base + 1, base, base, base], 30)) + + logging.info("Test excessive block propagation to nodes with different AD") + self.nodes[0].generate(1) + # it takes a while to sync all the txns + assert_equal(True, self.expectHeights([base + 2, base + 2, base, base], 500)) + + self.nodes[0].generate(1) + assert_equal(True, self.expectHeights([base + 3, base + 3, base + 3, base], 90)) + + self.nodes[0].generate(1) + assert_equal(True, self.expectHeights([base + 4, base + 4, base + 4, base + 4], 90)) + + logging.info("Excessive sigops test completed") + + # set it all back to defaults + + for n in self.nodes: + n.generate(150) + self.sync_blocks() + + self.nodes[0].set("net.excessiveSigopsPerMb=20000") # Set low so txns will fail if its used + self.nodes[1].set("net.excessiveSigopsPerMb=20000") + self.nodes[2].set("net.excessiveSigopsPerMb=20000") + self.nodes[3].set("net.excessiveSigopsPerMb=20000") + + self.nodes[0].setminingmaxblock(1000000) + self.nodes[1].setminingmaxblock(1000000) + self.nodes[2].setminingmaxblock(1000000) + self.nodes[3].setminingmaxblock(1000000) + self.nodes[0].set("net.excessiveBlock=1000000") + self.nodes[1].set("net.excessiveBlock=1000000") + self.nodes[2].set("net.excessiveBlock=1000000") + self.nodes[3].set("net.excessiveBlock=1000000") + + def testExcessiveTx(self): + """This test checks the behavior of the nodes in the presence of excessively large transactions. + It will set the accept depth to different values on each node, and then verify that each node + Does not follow the excessive tip until the accept depth is exceeded. + + The test also validates the rejection of a > 100kb transaction in a > 1MB block, and again + watches as each node eventually accepts the large tx based on accept depth. + """ + TEST_SIZE = 20 + logging.info("Test excessive transactions") + if 1: + tips = self.nodes[0].getchaintips() + + self.nodes[0].set("net.excessiveAcceptDepth=0") + self.nodes[1].set("net.excessiveAcceptDepth=1") + self.nodes[2].set("net.excessiveAcceptDepth=2") + self.nodes[3].set("net.excessiveAcceptDepth=3") + + self.nodes[0].set("net.excessiveBlock=2000000") + self.nodes[1].set("net.excessiveBlock=2000000") + self.nodes[2].set("net.excessiveBlock=2000000") + self.nodes[3].set("net.excessiveBlock=2000000") + + logging.info("Cleaning up node state") + for n in self.nodes: + n.generate(10) + self.sync_blocks() + + self.sync_all() + # verify mempool is cleaned up on all nodes + mbefore = [(lambda y: (y["size"], y["bytes"]))(x.getmempoolinfo()) for x in self.nodes] + assert_equal(mbefore, [(0, 0)] * 4) + + if 1: + logging.info("Creating addresses...") + self.nodes[0].keypoolrefill(TEST_SIZE + 1) + addrs = [self.nodes[0].getnewaddress() for _ in range(TEST_SIZE + 1)] + else: # enable if you are using a pre-created wallet, as described above + logging.info("Loading addresses...") + with open("wallet10kAddrs.json") as f: + addrs = json.load(f) + + if 1: # Test not relaying a large transaction + + # Make the excessive transaction size smaller so its quicker to produce a excessive one + self.nodes[0].set("net.excessiveTx=100000") + self.nodes[1].set("net.excessiveTx=100000") + self.nodes[2].set("net.excessiveTx=100000") + self.nodes[3].set("net.excessiveTx=100000") + self.nodes[0].setminingmaxblock(1000000) + self.nodes[1].setminingmaxblock(1000000) + self.nodes[2].setminingmaxblock(1000000) + self.nodes[3].setminingmaxblock(1000000) + + wallet = self.nodes[0].listunspent() + wallet.sort(key=lambda x: x["amount"], reverse=True) + while len(wallet) < 3000: + # Create a LOT of UTXOs + logging.info("Create lots of UTXOs...") + n = 0 + group = min(100, TEST_SIZE) + count = 0 + for w in wallet: + count += 1 + split_transaction(self.nodes[0], [w], addrs[n:group + n]) + n += group + if n >= len(addrs): + n = 0 + if count > 50: # We don't need any more + break + self.sync_all() + logging.info("mine blocks") + self.nodes[0].generate(5) # mine all the created transactions + logging.info("sync all blocks and mempools") + self.sync_all() + + wallet = self.nodes[0].listunspent() + wallet.sort(key=lambda x: x["amount"], reverse=True) + + logging.info("clean out the mempool") + mbefore = [(lambda y: (y["size"], y["bytes"]))(x.getmempoolinfo()) for x in self.nodes] + while mbefore != [(0, 0)] * 4: + time.sleep(1) + self.nodes[0].generate(1) + time.sleep(10) + mbefore = [(lambda y: (y["size"], y["bytes"]))(x.getmempoolinfo()) for x in self.nodes] + + # we need the mempool to be empty to track that this one tx doesn't prop + assert_equal(mbefore, [(0, 0)] * 4) + + logging.info("Test not relaying a large transaction") + + (tx, vin, vout, txid) = split_transaction(self.nodes[0], wallet[0:3000], [addrs[0]], txfeePer=60) + logging.debug("Transaction Length is: ", len(binascii.unhexlify(tx))) + assert(len(binascii.unhexlify(tx)) > 100000) # txn has to be big for the test to work + + mbefore = [(lambda y: (y["size"], y["bytes"]))(x.getmempoolinfo()) for x in self.nodes] + assert_equal(mbefore[1:], [(0, 0), (0, 0), (0, 0)]) # verify that the transaction did not propagate + assert(mbefore[0][0] > 0) # verify that the transaction is in my node + + logging.info("allowing tx a chance to propagate - sleeping...") + while len(self.nodes[0].getmempoolinfo()) < 1: + logging.info("sleeping 1") + time.sleep(1) + time.sleep(5) + + logging.info("Test a large transaction in block < 1MB") + largeBlock = self.nodes[0].generate(1) + self.sync_blocks() + counts = [x.getblockcount() for x in self.nodes] + latest = counts[0] + # Verify that all nodes accepted the block, even if some of them didn't + # have the transaction. They should all accept a <= 1MB block with a tx + # <= 1MB + assert_equal(counts, [latest, latest, latest, latest]) + + # this test checks the behavior of > 1MB blocks with excessive + # transactions. it takes a LONG time to generate and propagate 1MB+ txs. + if self.extended: + + logging.info("Creating addresses...") + self.nodes[0].keypoolrefill(2000) + addrs = [self.nodes[0].getnewaddress() for _ in range(2000)] + # Create a LOT of UTXOs for the next test + wallet = self.nodes[0].listunspent() + wallet.sort(key=lambda x: x["amount"], reverse=True) + wlen = len(wallet) + while wlen < 8000: + logging.info("Create lots of UTXOs by 100...") + n = 0 + for w in wallet: + split_transaction(self.nodes[0], [w], addrs[n:100 + n]) + logging.info(str(wlen)) + n += 100 + if n >= len(addrs): + n = 0 + wlen += 99 + if wlen > 8000: + break + + blk = self.nodes[0].generate(1) + blkinfo = self.nodes[0].getblock(blk[0]) + logging.info("Generated block %d size: %d, num tx: %d" % + (blkinfo["height"], blkinfo["size"], len(blkinfo["tx"]))) + wallet = self.nodes[0].listunspent() + wallet.sort(key=lambda x: x["amount"], reverse=True) + wlen = len(wallet) + + self.nodes[0].generate(1) + self.sync_all() + + logging.info("Building > 1MB block...") + # Set the excessive transaction size larger for this node so we can + # generate an "excessive" block for the other nodes + self.nodes[0].set("net.excessiveTx=1000000") + + self.generateTx(self.nodes[0], 1000000, addrs) + + # Now generate a > 100kb transaction & mine it into a > 1MB block + + self.nodes[0].setminingmaxblock(2000000) + self.nodes[0].set("net.excessiveBlock=2000000") + + wallet.sort(key=lambda x: x["amount"], reverse=True) + (tx, vin, vout, txid) = split_transaction(self.nodes[0], wallet[0:2500], [addrs[0]], txfeePer=60) + logging.debug("Transaction Length is: ", len(binascii.unhexlify(tx))) + assert(len(binascii.unhexlify(tx)) > 100000) # txn has to be big for the test to work + + origCounts = [x.getblockcount() for x in self.nodes] + base = origCounts[0] + mpool = [(lambda y: (y["size"], y["bytes"]))(x.getmempoolinfo()) for x in self.nodes] + logging.debug(str(mpool)) + largeBlock = self.nodes[0].generate(1) + mpool = [(lambda y: (y["size"], y["bytes"]))(x.getmempoolinfo()) for x in self.nodes] + logging.debug(str(mpool)) + + logging.info("Syncing node1") + largeBlock2 = self.nodes[0].generate(1) + sync_blocks(self.nodes[0:2]) + mpool = [(lambda y: (y["size"], y["bytes"]))(x.getmempoolinfo()) for x in self.nodes] + logging.debug(str(mpool)) + self.expectHeights([base + 2, base + 2, base, base], 30) + + logging.info("Syncing node2") + largeBlock3 = self.nodes[0].generate(1) + sync_blocks(self.nodes[0:3]) + self.expectHeights([base + 3, base + 3, base + 3, base], 30) + + logging.info("Syncing node3") + largeBlock4 = self.nodes[0].generate(1) + sync_blocks(self.nodes) + self.expectHeights([base + 4, base + 4, base + 4, base + 4], 30) + + # Put it back to the default + self.nodes[0].set("net.excessiveTx=1000000") + self.nodes[1].set("net.excessiveTx=1000000") + self.nodes[2].set("net.excessiveTx=1000000") + self.nodes[3].set("net.excessiveTx=1000000") + + def repeatTx(self, count, node, addr, amt=1.0): + for i in range(0, count): + node.sendtoaddress(addr, amt) + + def generateAndPrintBlock(self, node): + hsh = node.generate(1) + inf = node.getblock(hsh[0]) + logging.info("block %d size %d" % (inf["height"], inf["size"])) + return hsh + + def testExcessiveBlockSize(self): + + # get spendable coins + if 0: + for n in self.nodes: + n.generate(1) + self.sync_all() + self.nodes[0].generate(100) + + self.sync_all() + + # Set the accept depth at 1, 2, and 3 and watch each nodes resist the chain for that long + self.nodes[0].setminingmaxblock(5000) # keep the generated blocks within 16*the EB so no disconnects + self.nodes[1].setminingmaxblock(1000) + self.nodes[2].setminingmaxblock(1000) + self.nodes[3].setminingmaxblock(1000) + + self.nodes[1].setexcessiveblock(1000, 1) + self.nodes[2].setexcessiveblock(1000, 2) + self.nodes[3].setexcessiveblock(1000, 3) + + logging.info("Test excessively sized block, not propagating until accept depth is exceeded") + addr = self.nodes[3].getnewaddress() + # By using a very small value, it is likely that a single input is used. This is important because + # our mined block size is so small in this test that if multiple inputs are used the transactions + # might not fit in the block. This will give us a short block when the test expects a larger one. + # To catch any of these short-block test malfunctions, the block size is printed out. + self.repeatTx(8, self.nodes[0], addr, .001) + counts = [x.getblockcount() for x in self.nodes] + base = counts[0] + logging.info("Starting counts: %s" % str(counts)) + logging.info("node0") + self.generateAndPrintBlock(self.nodes[0]) + time.sleep(2) # give blocks a chance to fully propagate + counts = [x.getblockcount() for x in self.nodes] + assert_equal(counts, [base + 1, base, base, base]) + + logging.info("node1") + self.nodes[0].generate(1) + sync_blocks(self.nodes[0:2]) + counts = [x.getblockcount() for x in self.nodes] + assert_equal(counts, [base + 2, base + 2, base, base]) + + logging.info("node2") + self.nodes[0].generate(1) + sync_blocks(self.nodes[0:3]) + counts = [x.getblockcount() for x in self.nodes] + assert_equal(counts, [base + 3, base + 3, base + 3, base]) + + logging.info("node3") + self.nodes[0].generate(1) + self.sync_all() + counts = [x.getblockcount() for x in self.nodes] + assert_equal(counts, [base + 4] * 4) + + # Now generate another excessive block, but all nodes should snap right to + # it because they have an older excessive block + logging.info("Test immediate propagation of additional excessively sized block, due to prior excessive") + self.repeatTx(8, self.nodes[0], addr, .001) + self.nodes[0].generate(1) + self.sync_all() + counts = [x.getblockcount() for x in self.nodes] + assert_equal(counts, [base + 5] * 4) + + logging.info("Test daily excessive reset") + # Now generate a day's worth of small blocks which should re-enable the + # node's reluctance to accept a large block + self.nodes[0].generate(6 * 24) + sync_blocks(self.nodes) + self.nodes[0].generate(5) # plus the accept depths + sync_blocks(self.nodes) + self.repeatTx(8, self.nodes[0], addr, .001) + base = self.nodes[0].getblockcount() + print("base: %d" % base) + self.generateAndPrintBlock(self.nodes[0]) + time.sleep(2) # give blocks a chance to fully propagate + counts = [x.getblockcount() for x in self.nodes] + assert_equal(counts, [base + 1, base, base, base]) + + self.repeatTx(8, self.nodes[0], addr, .001) + self.generateAndPrintBlock(self.nodes[0]) + time.sleep(2) # give blocks a chance to fully propagate + sync_blocks(self.nodes[0:2]) + counts = [x.getblockcount() for x in self.nodes] + assert_equal(counts, [base + 2, base + 2, base, base]) + + self.repeatTx(5, self.nodes[0], addr, .001) + self.generateAndPrintBlock(self.nodes[0]) + time.sleep(2) # give blocks a chance to fully propagate + sync_blocks(self.nodes[0:3]) + counts = [x.getblockcount() for x in self.nodes] + assert_equal(counts, [base + 3, base + 3, base + 3, base]) + + self.repeatTx(5, self.nodes[0], addr, .001) + self.generateAndPrintBlock(self.nodes[0]) + sync_blocks(self.nodes) + counts = [x.getblockcount() for x in self.nodes] + assert_equal(counts, [base + 4] * 4) + + self.repeatTx(5, self.nodes[0], addr, .001) + self.generateAndPrintBlock(self.nodes[0]) + sync_blocks(self.nodes) + counts = [x.getblockcount() for x in self.nodes] + assert_equal(counts, [base + 5] * 4) + + logging.info("Test daily excessive reset #2") + # Now generate a day's worth of small blocks which should re-enable the + # node's reluctance to accept a large block + 10 because we have to get + # beyond all the node's accept depths + self.nodes[0].generate(6 * 24 + 10) + sync_blocks(self.nodes) + + # counts = [ x.getblockcount() for x in self.nodes ] + self.nodes[1].setexcessiveblock(100000, 1) # not sure how big the txns will be but smaller than this + self.nodes[1].setminingmaxblock(100000) # not sure how big the txns will be but smaller than this + self.repeatTx(20, self.nodes[0], addr, .001) + base = self.nodes[0].getblockcount() + self.generateAndPrintBlock(self.nodes[0]) + time.sleep(2) # give blocks a chance to fully propagate + sync_blocks(self.nodes[0:2]) + counts = [x.getblockcount() for x in self.nodes] + assert_equal(counts, [base + 1, base + 1, base, base]) + + logging.info("Random test") + if self.extended: + randomRange = 3 + else: + randomRange = 2 + + for i in range(0, randomRange): + logging.info("round %d" % i) + for n in self.nodes: + size = random.randint(1, 1000) * 1000 + try: # since miningmaxblock must be <= excessiveblock, raising/lowering may need to run these in different order + n.setminingmaxblock(size) + n.setexcessiveblock(size, random.randint(0, 10)) + except JSONRPCException: + n.setexcessiveblock(size, random.randint(0, 10)) + n.setminingmaxblock(size) + + addrs = [x.getnewaddress() for x in self.nodes] + ntxs = 0 + for i in range(0, random.randint(1, 200)): + try: + self.nodes[random.randint(0, 3)].sendtoaddress(addrs[random.randint(0, 3)], .1) + ntxs += 1 + except JSONRPCException: # could be spent all the txouts + pass + logging.info("%d transactions" % ntxs) + time.sleep(1) # allow txns a chance to propagate + self.nodes[random.randint(0, 3)].generate(1) + logging.info("mined a block") + # TODO: rather than sleeping we should really be putting a check in here + # based on what the random excessive seletions were from above + time.sleep(5) # allow block a chance to propagate + + # the random test can cause disconnects if the block size is very large compared to excessive size + # so reconnect + interconnect_nodes(self.nodes) + + +if __name__ == '__main__': + + if "--extensive" in sys.argv: + longTest = True + # we must remove duplicate 'extensive' arg here + while True: + try: + sys.argv.remove('--extensive') + except: + break + logging.info("Running extensive tests") + else: + longTest = False + + ExcessiveBlockTest(longTest).main() + + +def info(type, value, tb): + if hasattr(sys, 'ps1') or not sys.stderr.isatty(): + # we are in interactive mode or we don't have a tty-like + # device, so we call the default hook + sys.__excepthook__(type, value, tb) + else: + import traceback + import pdb + # we are NOT in interactive mode, print the exception... + traceback.print_exception(type, value, tb) + print + # ...then start the debugger in post-mortem mode. + pdb.pm() + + +sys.excepthook = info + + +def Test(): + t = ExcessiveBlockTest(True) + bitcoinConf = { + "debug": ["net", "blk", "thin", "mempool", "req", "bench", "evict"], # "lck" + "blockprioritysize": 2000000 # we don't want any transactions rejected due to insufficient fees... + } + t.main(["--tmpdir=/ramdisk/test", "--nocleanup", "--noshutdown"], bitcoinConf, None) diff --git a/qa/rpc-tests/forknotify.py b/qa/rpc-tests/forknotify.py new file mode 100644 index 00000000..674df76f --- /dev/null +++ b/qa/rpc-tests/forknotify.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test -alertnotify +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class ForkNotifyTest(BitcoinTestFramework): + + alert_filename = None # Set by setup_network + + def setup_network(self): + self.nodes = [] + self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") + with open(self.alert_filename, 'w') as f: + pass # Just open then close to create zero-length file + self.nodes.append(start_node(0, self.options.tmpdir, + ["-blockversion=2", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""])) + # Node1 mines block.version=211 blocks + self.nodes.append(start_node(1, self.options.tmpdir, + ["-blockversion=211"])) + connect_nodes(self.nodes[1], 0) + + self.is_network_split = False + self.sync_all() + + def run_test(self): + # Mine 51 up-version blocks + self.nodes[1].generate(51) + self.sync_all() + # -alertnotify should trigger on the 51'st, + # but mine and sync another to give + # -alertnotify time to write + self.nodes[1].generate(1) + self.sync_all() + + with open(self.alert_filename, 'r') as f: + alert_text = f.read() + + if len(alert_text) == 0: + raise AssertionError("-alertnotify did not warn of up-version blocks") + + # Mine more up-version blocks, should not get more alerts: + self.nodes[1].generate(1) + self.sync_all() + self.nodes[1].generate(1) + self.sync_all() + + with open(self.alert_filename, 'r') as f: + alert_text2 = f.read() + + if alert_text != alert_text2: + raise AssertionError("-alertnotify excessive warning of up-version blocks") + +if __name__ == '__main__': + ForkNotifyTest().main() diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py new file mode 100644 index 00000000..83cb489d --- /dev/null +++ b/qa/rpc-tests/fundrawtransaction.py @@ -0,0 +1,673 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +import pdb +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +# Create one-input, one-output, no-fee transaction: +class RawTransactionsTest(BitcoinTestFramework): + + def setup_chain(self, bitcoinConfDict=None, wallets=None): + print(("Initializing test directory "+self.options.tmpdir)) + initialize_chain_clean(self.options.tmpdir, 4, bitcoinConfDict, wallets) + + def setup_network(self, split=False): + self.nodes = start_nodes(4, self.options.tmpdir) + + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + connect_nodes_bi(self.nodes,0,3) + + self.is_network_split=False + self.sync_all() + + def run_test(self): + print("Mining blocks...") + + min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee'] + # This test is not meant to test fee estimation and we'd like + # to be sure all txs are sent at a consistent desired feerate + for node in self.nodes: + node.settxfee(min_relay_tx_fee) + + # if the fee's positive delta is higher than this value tests will fail, + # neg. delta always fail the tests. + # The size of the signature of every input may be at most 2 bytes larger + # than a minimum sized signature. + + # = 2 bytes * minRelayTxFeePerByte + feeTolerance = 2 * min_relay_tx_fee/1000 + + self.nodes[2].generate(1) + self.sync_all() + self.nodes[0].generate(121) + self.sync_all() + + watchonly_address = self.nodes[0].getnewaddress() + watchonly_pubkey = self.nodes[0].validateaddress(watchonly_address)["pubkey"] + watchonly_amount = Decimal(200) + self.nodes[3].importpubkey(watchonly_pubkey, "", True) + watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address, watchonly_amount) + self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(), watchonly_amount / 10) + + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5) + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0) + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0) + + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + ############### + # simple test # + ############### + inputs = [ ] + outputs = { self.nodes[0].getnewaddress() : 1.0 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + assert(len(dec_tx['vin']) > 0) #test if we have enought inputs + + ############################# + # test preserving nLockTime # + ############################# + inputs = [ ] + outputs = { self.nodes[0].getnewaddress() : 1.0 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs,1234) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + assert(dec_tx["locktime"] == 1234) + + ################################ + # test using default nLockTime # + ################################ + blockcount = self.nodes[0].getblockcount() + inputs = [ ] + outputs = { self.nodes[0].getnewaddress() : 1.0 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + + # there's a random chance of an earlier locktime so iterate a few times + for i in range(0,20): + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + if dec_tx["locktime"] == blockcount: + break + assert(dec_tx["locktime"] > 0) + assert(i<18) # incrediably unlikely to never produce the current blockcount + + ############################## + # simple test with two coins # + ############################## + inputs = [ ] + outputs = { self.nodes[0].getnewaddress() : 2.2 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + assert(len(dec_tx['vin']) > 0) #test if we have enough inputs + + ############################## + # simple test with two coins # + ############################## + inputs = [ ] + outputs = { self.nodes[0].getnewaddress() : 2.6 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + assert(len(dec_tx['vin']) > 0) + assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') + + + ################################ + # simple test with two outputs # + ################################ + inputs = [ ] + outputs = { self.nodes[0].getnewaddress() : 2.6, self.nodes[1].getnewaddress() : 2.5 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + + assert(len(dec_tx['vin']) > 0) + assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') + + + ######################################################################### + # test a fundrawtransaction with a VIN greater than the required amount # + ######################################################################### + utx = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 5.0: + utx = aUtx + break + + assert(utx!=False) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] + outputs = { self.nodes[0].getnewaddress() : 1.0 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + + assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee + + + ##################################################################### + # test a fundrawtransaction with which will not get a change output # + ##################################################################### + utx = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 5.0: + utx = aUtx + break + + assert(utx!=False) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] + outputs = { self.nodes[0].getnewaddress() : Decimal(5.0) - fee } # - feeTolerance } # BU having the fee tolerance in there creates a very small change output + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + txfee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + + assert_equal(rawtxfund['changepos'], -1) + assert_equal(txfee + totalOut, utx['amount']) #compare vin total and totalout+fee + + + ######################################################################### + # test a fundrawtransaction with a VIN smaller than the required amount # + ######################################################################### + utx = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 1.0: + utx = aUtx + break + + assert(utx!=False) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] + outputs = { self.nodes[0].getnewaddress() : 1.0 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + + # 4-byte version + 1-byte vin count + 36-byte prevout then script_len + rawtx = rawtx[:82] + "0100" + rawtx[84:] + + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex']) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + matchingOuts = 0 + for i, out in enumerate(dec_tx['vout']): + totalOut += out['value'] + if out['scriptPubKey']['addresses'][0] in outputs: + matchingOuts+=1 + else: + assert_equal(i, rawtxfund['changepos']) + + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex']) + + assert_equal(matchingOuts, 1) + assert_equal(len(dec_tx['vout']), 2) + + + ########################################### + # test a fundrawtransaction with two VINs # + ########################################### + utx = False + utx2 = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 1.0: + utx = aUtx + if aUtx['amount'] == 5.0: + utx2 = aUtx + + + assert(utx!=False) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ] + outputs = { self.nodes[0].getnewaddress() : 6.0 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + matchingOuts = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + if out['scriptPubKey']['addresses'][0] in outputs: + matchingOuts+=1 + + assert_equal(matchingOuts, 1) + assert_equal(len(dec_tx['vout']), 2) + + matchingIns = 0 + for vinOut in dec_tx['vin']: + for vinIn in inputs: + if vinIn['txid'] == vinOut['txid']: + matchingIns+=1 + + assert_equal(matchingIns, 2) #we now must see two vins identical to vins given as params + + ######################################################### + # test a fundrawtransaction with two VINs and two vOUTs # + ######################################################### + utx = False + utx2 = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 1.0: + utx = aUtx + if aUtx['amount'] == 5.0: + utx2 = aUtx + + + 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 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + matchingOuts = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + if out['scriptPubKey']['addresses'][0] in outputs: + matchingOuts+=1 + + assert_equal(matchingOuts, 2) + assert_equal(len(dec_tx['vout']), 3) + + ############################################## + # test a fundrawtransaction with invalid vin # + ############################################## + listunspent = self.nodes[2].listunspent() + inputs = [ {'txid' : "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1", 'vout' : 0} ] #invalid vin! + outputs = { self.nodes[0].getnewaddress() : 1.0} + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + + try: + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + raise AssertionError("Spent more than available") + except JSONRPCException as e: + assert("Insufficient" in e.error['message']) + + + ############################################################ + #compare fee of a standard pubkeyhash transaction + inputs = [] + outputs = {self.nodes[1].getnewaddress():1.1} + rawTx = self.nodes[0].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[0].fundrawtransaction(rawTx) + + #create same transaction over sendtoaddress + txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1) + signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] + + #compare fee + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) + assert(feeDelta >= 0 and feeDelta <= feeTolerance) + ############################################################ + + ############################################################ + #compare fee of a standard pubkeyhash transaction with multiple outputs + inputs = [] + outputs = {self.nodes[1].getnewaddress():1.1,self.nodes[1].getnewaddress():1.2,self.nodes[1].getnewaddress():0.1,self.nodes[1].getnewaddress():1.3,self.nodes[1].getnewaddress():0.2,self.nodes[1].getnewaddress():0.3} + rawTx = self.nodes[0].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[0].fundrawtransaction(rawTx) + #create same transaction over sendtoaddress + txId = self.nodes[0].sendmany("", outputs) + signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] + + #compare fee + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) + assert(feeDelta >= 0 and feeDelta <= feeTolerance) + ############################################################ + + + ############################################################ + #compare fee of a 2of2 multisig p2sh transaction + + # create 2of2 addr + addr1 = self.nodes[1].getnewaddress() + addr2 = self.nodes[1].getnewaddress() + + addr1Obj = self.nodes[1].validateaddress(addr1) + addr2Obj = self.nodes[1].validateaddress(addr2) + + mSigObj = self.nodes[1].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) + + inputs = [] + outputs = {mSigObj:1.1} + rawTx = self.nodes[0].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[0].fundrawtransaction(rawTx) + + #create same transaction over sendtoaddress + txId = self.nodes[0].sendtoaddress(mSigObj, 1.1) + signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] + + #compare fee + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) + assert(feeDelta >= 0 and feeDelta <= feeTolerance) + ############################################################ + + + ############################################################ + #compare fee of a standard pubkeyhash transaction + + # create 4of5 addr + addr1 = self.nodes[1].getnewaddress() + addr2 = self.nodes[1].getnewaddress() + addr3 = self.nodes[1].getnewaddress() + addr4 = self.nodes[1].getnewaddress() + addr5 = self.nodes[1].getnewaddress() + + addr1Obj = self.nodes[1].validateaddress(addr1) + addr2Obj = self.nodes[1].validateaddress(addr2) + addr3Obj = self.nodes[1].validateaddress(addr3) + addr4Obj = self.nodes[1].validateaddress(addr4) + addr5Obj = self.nodes[1].validateaddress(addr5) + + mSigObj = self.nodes[1].addmultisigaddress(4, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey'], addr4Obj['pubkey'], addr5Obj['pubkey']]) + + inputs = [] + outputs = {mSigObj:1.1} + rawTx = self.nodes[0].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[0].fundrawtransaction(rawTx) + + #create same transaction over sendtoaddress + txId = self.nodes[0].sendtoaddress(mSigObj, 1.1) + signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] + + #compare fee + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) + assert(feeDelta >= 0 and feeDelta <= feeTolerance) + ############################################################ + + + ############################################################ + # spend a 2of2 multisig transaction over fundraw + + # create 2of2 addr + addr1 = self.nodes[2].getnewaddress() + addr2 = self.nodes[2].getnewaddress() + + addr1Obj = self.nodes[2].validateaddress(addr1) + addr2Obj = self.nodes[2].validateaddress(addr2) + + mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) + + + # send 1.2 BTC to msig addr + txId = self.nodes[0].sendtoaddress(mSigObj, 1.2) + self.sync_all() + self.nodes[1].generate(1) + self.sync_all() + + oldBalance = self.nodes[1].getbalance() + inputs = [] + outputs = {self.nodes[1].getnewaddress():1.1} + rawTx = self.nodes[2].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[2].fundrawtransaction(rawTx) + + signedTx = self.nodes[2].signrawtransaction(fundedTx['hex']) + txId = self.nodes[2].sendrawtransaction(signedTx['hex']) + self.sync_all() + self.nodes[1].generate(1) + self.sync_all() + + # make sure funds are received at node1 + assert_equal(oldBalance+Decimal('1.10000000'), self.nodes[1].getbalance()) + + ############################################################ + # locked wallet test + self.nodes[1].encryptwallet("test") + self.nodes.pop(1) + stop_nodes(self.nodes) + wait_bitcoinds() + + self.nodes = start_nodes(4, self.options.tmpdir) + # This test is not meant to test fee estimation and we'd like + # to be sure all txs are sent at a consistent desired feerate + for node in self.nodes: + node.settxfee(min_relay_tx_fee) + + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + connect_nodes_bi(self.nodes,0,3) + self.is_network_split=False + self.sync_all() + + # drain the keypool + self.nodes[1].getnewaddress() + inputs = [] + outputs = {self.nodes[0].getnewaddress():1.1} + rawTx = self.nodes[1].createrawtransaction(inputs, outputs) + # fund a transaction that requires a new key for the change output + # creating the key must be impossible because the wallet is locked + try: + fundedTx = self.nodes[1].fundrawtransaction(rawTx) + raise AssertionError("Wallet unlocked without passphrase") + except JSONRPCException as e: + assert('Keypool ran out' in e.error['message']) + + #refill the keypool + self.nodes[1].walletpassphrase("test", 100) + self.nodes[1].walletlock() + + try: + self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2) + raise AssertionError("Wallet unlocked without passphrase") + except JSONRPCException as e: + assert('walletpassphrase' in e.error['message']) + + oldBalance = self.nodes[0].getbalance() + + inputs = [] + outputs = {self.nodes[0].getnewaddress():1.1} + rawTx = self.nodes[1].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[1].fundrawtransaction(rawTx) + + #now we need to unlock + self.nodes[1].walletpassphrase("test", 100) + signedTx = self.nodes[1].signrawtransaction(fundedTx['hex']) + txId = self.nodes[1].sendrawtransaction(signedTx['hex']) + self.sync_all() + self.nodes[1].generate(1) + self.sync_all() + + # make sure funds are received at node1 + assert_equal(oldBalance+Decimal('51.10000000'), self.nodes[0].getbalance()) + + + ############################################### + # multiple (~19) inputs tx test | Compare fee # + ############################################### + + #empty node1, send some small coins from node0 to node1 + self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + for i in range(0,20): + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + #fund a tx with ~20 small inputs + inputs = [] + outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04} + rawTx = self.nodes[1].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[1].fundrawtransaction(rawTx) + + #create same transaction over sendtoaddress + txId = self.nodes[1].sendmany("", outputs) + signedFee = self.nodes[1].getrawmempool(True)[txId]['fee'] + + #compare fee + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) + assert(feeDelta >= 0 and feeDelta <= feeTolerance*19) #~19 inputs + + + ############################################# + # multiple (~19) inputs tx test | sign/send # + ############################################# + + #again, empty node1, send some small coins from node0 to node1 + self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + for i in range(0,20): + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + #fund a tx with ~20 small inputs + oldBalance = self.nodes[0].getbalance() + + inputs = [] + outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04} + rawTx = self.nodes[1].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[1].fundrawtransaction(rawTx) + fundedAndSignedTx = self.nodes[1].signrawtransaction(fundedTx['hex']) + txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex']) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + assert_equal(oldBalance+Decimal('50.19000000'), self.nodes[0].getbalance()) #0.19+block reward + + ##################################################### + # test fundrawtransaction with OP_RETURN and no vin # + ##################################################### + + rawtx = "0100000000010000000000000000066a047465737400000000" + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + + assert_equal(len(dec_tx['vin']), 0) + assert_equal(len(dec_tx['vout']), 1) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + + assert_greater_than(len(dec_tx['vin']), 0) # at least one vin + assert_equal(len(dec_tx['vout']), 2) # one change output added + + + ################################################## + # test a fundrawtransaction using only watchonly # + ################################################## + + inputs = [] + outputs = {self.nodes[2].getnewaddress() : watchonly_amount / 2} + rawtx = self.nodes[3].createrawtransaction(inputs, outputs) + + result = self.nodes[3].fundrawtransaction(rawtx, True) + res_dec = self.nodes[0].decoderawtransaction(result["hex"]) + assert_equal(len(res_dec["vin"]), 1) + assert_equal(res_dec["vin"][0]["txid"], watchonly_txid) + + assert("fee" in result.keys()) + assert_greater_than(result["changepos"], -1) + + ############################################################### + # test fundrawtransaction using the entirety of watched funds # + ############################################################### + + inputs = [] + outputs = {self.nodes[2].getnewaddress() : watchonly_amount} + rawtx = self.nodes[3].createrawtransaction(inputs, outputs) + + result = self.nodes[3].fundrawtransaction(rawtx, True) + res_dec = self.nodes[0].decoderawtransaction(result["hex"]) + assert_equal(len(res_dec["vin"]), 2) + assert(res_dec["vin"][0]["txid"] == watchonly_txid or res_dec["vin"][1]["txid"] == watchonly_txid) + + assert_greater_than(result["fee"], 0) + assert_greater_than(result["changepos"], -1) + assert_equal(result["fee"] + res_dec["vout"][result["changepos"]]["value"], watchonly_amount / 10) + + signedtx = self.nodes[3].signrawtransaction(result["hex"]) + assert(not signedtx["complete"]) + signedtx = self.nodes[0].signrawtransaction(signedtx["hex"]) + assert(signedtx["complete"]) + self.nodes[0].sendrawtransaction(signedtx["hex"]) + + self.nodes[0].generate(1) + self.sync_all() + + ################################ + # Test no address reuse occurs # + ################################ + + inputs = [] + outputs = {self.nodes[2].getnewaddress() : 1} + rawtx = self.nodes[3].createrawtransaction(inputs, outputs) + result3 = self.nodes[3].fundrawtransaction(rawtx) + res_dec = self.nodes[0].decoderawtransaction(result3["hex"]) + changeaddress = "" + for out in res_dec['vout']: + if out['value'] > 1.0: + changeaddress += out['scriptPubKey']['addresses'][0] + assert(changeaddress != "") + nextaddr = self.nodes[3].getnewaddress() + # Now the change address key should be removed from the keypool + assert(changeaddress != nextaddr) + +if __name__ == '__main__': + RawTransactionsTest().main(None,{"keypool":1}) diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/qa/rpc-tests/getblocktemplate_longpoll.py new file mode 100644 index 00000000..84eab6a1 --- /dev/null +++ b/qa/rpc-tests/getblocktemplate_longpoll.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +import threading + +class LongpollThread(threading.Thread): + def __init__(self, node): + threading.Thread.__init__(self) + # query current longpollid + templat = node.getblocktemplate() + self.longpollid = templat['longpollid'] + # create a new connection to the node, we can't use the same + # connection from two threads + self.node = get_rpc_proxy(node.url, 1, timeout=600) + + def run(self): + self.node.getblocktemplate({'longpollid':self.longpollid}) + +class GetBlockTemplateLPTest(BitcoinTestFramework): + ''' + Test longpolling with getblocktemplate. + ''' + + def run_test(self): + print("Warning: this test will take about 70 seconds in the best case. Be patient.") + self.nodes[0].generate(10) + self.sync_all() + templat = self.nodes[0].getblocktemplate() + longpollid = templat['longpollid'] + # longpollid should not change between successive invocations if nothing else happens + templat2 = self.nodes[0].getblocktemplate() + assert(templat2['longpollid'] == longpollid) + + # Test 1: test that the longpolling wait if we do nothing + thr = LongpollThread(self.nodes[0]) + thr.start() + # check that thread still lives + thr.join(5) # wait 5 seconds or until thread exits + assert(thr.is_alive()) + + # Test 2: test that longpoll will terminate if another node generates a block + self.nodes[1].generate(1) # generate a block on another node + # check that thread will exit now that new transaction entered mempool + thr.join(5) # wait 5 seconds or until thread exits + assert(not thr.is_alive()) + + # Test 3: test that longpoll will terminate if we generate a block ourselves + thr = LongpollThread(self.nodes[0]) + thr.start() + self.nodes[0].generate(1) # generate a block on another node + thr.join(5) # wait 5 seconds or until thread exits + assert(not thr.is_alive()) + + # Test 4: test that introducing a new transaction into the mempool will terminate the longpoll + thr = LongpollThread(self.nodes[0]) + thr.start() + # generate a random transaction and submit it + (txid, txhex, fee) = random_transaction(self.nodes, Decimal("1.1"), Decimal("0.0"), Decimal("0.001"), 20) + # after one minute, every 10 seconds the mempool is probed, so in 80 seconds it should have returned + thr.join(60 + 20) + assert(not thr.is_alive()) + +if __name__ == '__main__': + GetBlockTemplateLPTest().main() + diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py new file mode 100644 index 00000000..848a9b68 --- /dev/null +++ b/qa/rpc-tests/getblocktemplate_proposals.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +from binascii import a2b_hex, b2a_hex +from hashlib import sha256 +from struct import pack + +def b2x(b): + return b2a_hex(b).decode('ascii') + +# NOTE: This does not work for signed numbers (set the high bit) or zero (use b'\0') +def encodeUNum(n): + s = bytearray(b'\1') + while n > 127: + s[0] += 1 + s.append(n % 256) + n //= 256 + s.append(n) + return bytes(s) + +def varlenEncode(n): + if n < 0xfd: + return pack(' 1: + n = [] + if len(cur) & 1: + cur.append(cur[-1]) + for i in range(0, len(cur), 2): + n.append(dblsha(cur[i] + cur[i+1])) + cur = n + return cur[0] + +def template_to_bytearray(tmpl, txlist): + blkver = pack('= 50000: + self.connection.send_message(msg_inv(current_invs)) + current_invs = [] + if len(current_invs) > 0: + self.connection.send_message(msg_inv(current_invs)) + print ("requesting " + str(len(current_invs)) + " blocks") + + # Wait and see how many blocks were requested + time.sleep(2) + + total_requests = 0 + with mininode_lock: + for key in self.blockReqCounts: + total_requests += self.blockReqCounts[key] + if self.blockReqCounts[key] > 1: + raise AssertionError("Error, test failed: block %064x requested more than once" % key) + if total_requests > MAX_REQUESTS: + raise AssertionError("Error, too many blocks (%d) requested" % total_requests) + if total_requests < numBlocksToGenerate[count]: + raise AssertionError("Error, not enough blocks (%d) requested" % total_requests) + print("Round %d: success (total requests: %d)" % (count, total_requests)) + self.blockReqCounts = {} + + self.disconnectOkay = True + self.connection.disconnect_node() + + +class MaxBlocksInFlightTest(BitcoinTestFramework): + def add_options(self, parser): + parser.add_option("--testbinary", dest="testbinary", + default=os.getenv("BITCOIND", "bitcoind"), + help="Binary to test max block requests behavior") + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self): + self.nodes = start_nodes(1, self.options.tmpdir, + extra_args=[['-debug', '-whitelist=127.0.0.1']], + binary=[self.options.testbinary]) + + def run_test(self): + test = TestManager() + test.add_new_connection(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test)) + NetworkThread().start() # Start up network handling in another thread + test.run() + +if __name__ == '__main__': + MaxBlocksInFlightTest().main() diff --git a/qa/rpc-tests/maxuploadtarget.py b/qa/rpc-tests/maxuploadtarget.py new file mode 100644 index 00000000..2ed13123 --- /dev/null +++ b/qa/rpc-tests/maxuploadtarget.py @@ -0,0 +1,328 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.mininode import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import time + +''' +Test behavior of -maxuploadtarget. + +* Verify that getdata requests for old blocks (>1week) are dropped +if uploadtarget has been reached. +* Verify that getdata requests for recent blocks are respecteved even +if uploadtarget has been reached. +* Verify that the upload counters are reset after 24 hours. +''' + +# BU: the EB parameter now controls the daily buffer size (the amount of +# data that a peer can upload before the user-specified maxuploadtarget +# parameter actually takes effect. +# EB in this test is set to match the historic size, which resulted in +# a daily buffer of 144 * 1MB. +# But it is possible to adjust it (pick a multiple of 1MB below) and +# tests should pass. This has been tested up to 16MB. +EXCESSIVE_BLOCKSIZE = 1000000 # bytes +print ("running with -excessiveblocksize = %s bytes" % EXCESSIVE_BLOCKSIZE) + +# sync_with_ping() timeouts also need to scale with block size +# (this has been determined empirically) +# The formula below allows a sync timeout to scale up sufficiently to pass +# even with 16MB blocks (tested on a reasonably fast machine). +# The baseline has been increased from 30s to 60s which enables the test +# to pass with 1MB on a slow i686 machine. Raising the baseline timeout +# does not increase the test duration on faster machines. +SYNC_WITH_PING_TIMEOUT = 60 + 20 * int((max(1000000, EXCESSIVE_BLOCKSIZE)-1000000) / 1000000) # seconds +print ("sync_with_ping timeout = %s sec" % SYNC_WITH_PING_TIMEOUT) + + +# 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() + self.block_receive_map = {} + + def add_connection(self, conn): + self.connection = conn + self.peer_disconnected = False + + def on_inv(self, conn, message): + pass + + # Track the last getdata message we receive (used in the test) + def on_getdata(self, conn, message): + self.last_getdata = message + + def on_block(self, conn, message): + message.block.calc_sha256() + try: + self.block_receive_map[message.block.sha256] += 1 + except KeyError as e: + self.block_receive_map[message.block.sha256] = 1 + + # Spin until verack message is received from the node. + # We use this to signal that our test can begin. This + # is called from the testing thread, so it needs to acquire + # the global lock. + def wait_for_verack(self): + def veracked(): + return self.verack_received + return wait_until(veracked, timeout=10) + + def wait_for_disconnect(self): + def disconnected(): + return self.peer_disconnected + return wait_until(disconnected, timeout=10) + + # Wrapper for the NodeConn's send_message function + def send_message(self, message): + self.connection.send_message(message) + + def on_pong(self, conn, message): + self.last_pong = message + + def on_close(self, conn): + self.peer_disconnected = True + + # Sync up with the node after delivery of a block + def sync_with_ping(self, timeout=SYNC_WITH_PING_TIMEOUT): + def received_pong(): + return (self.last_pong.nonce == self.ping_counter) + self.connection.send_message(msg_ping(nonce=self.ping_counter)) + success = wait_until(received_pong, timeout) + self.ping_counter += 1 + return success + +class MaxUploadTest(BitcoinTestFramework): + def __init__(self): + self.utxo = [] + self.txouts = gen_return_txouts() + + def add_options(self, parser): + parser.add_option("--testbinary", dest="testbinary", + default=os.getenv("BITCOIND", "bitcoind"), + help="bitcoind binary to test") + + def setup_chain(self): + initialize_chain_clean(self.options.tmpdir, 2) + + def setup_network(self): + # Start a node with maxuploadtarget of 200*EB (MB/24h) + # some other attributes defined below have been factored out of + # other methods in this class. + self.nodes = [] + # an overhead factor approximates how the traffic with bigger blocks + self.overhead_factor_a = 10 # percent + print ("overhead_factor = %s %%" % self.overhead_factor_a) + # maxuploadtarget (unit: MiB) was 200 originally, now scale with EB + self.maxuploadtarget = int(200 * EXCESSIVE_BLOCKSIZE / 1000000) + print ("maxuploadtarget = %sMiB" % self.maxuploadtarget) + self.blockmaxsize = EXCESSIVE_BLOCKSIZE-1000 # EB-1KB + print ("blockmaxsize = %s bytes" % self.blockmaxsize) + self.max_bytes_per_day = self.maxuploadtarget * 1024 * 1024 + print ("max_bytes_per_day = %s bytes" % self.max_bytes_per_day) + self.daily_buffer = 144 * EXCESSIVE_BLOCKSIZE + print ("daily buffer = %s bytes" % self.daily_buffer) + self.max_bytes_available = self.max_bytes_per_day - self.daily_buffer + print ("max_bytes_available = %s bytes" % self.max_bytes_available) + # roughly how many 66k transactions we need to create a big block + self.num_transactions = int(EXCESSIVE_BLOCKSIZE / 66000) - 1 + print ("num txs in big block = %s" % self.num_transactions) + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", + "-use-thinblocks=0", # turned off to predict size of transmitted data + "-excessiveblocksize=%s" % EXCESSIVE_BLOCKSIZE, + "-maxuploadtarget=%s" % self.maxuploadtarget, + "-blockmaxsize=%s" % self.blockmaxsize])) + + def mine_big_block(self, node, address): + # Want to create a big block + # We'll generate a 66k transaction below + for j in range(self.num_transactions): + if len(self.utxo) < self.num_transactions: + self.utxo = node.listunspent() + inputs=[] + outputs = {} + t = self.utxo.pop() + inputs.append({ "txid" : t["txid"], "vout" : t["vout"]}) + remchange = t["amount"] - Decimal("0.001000") + outputs[address]=remchange + # Create a basic transaction that will send change back to ourself after account for a fee + # And then insert the 128 generated transaction outs in the middle rawtx[92] is where the # + # of txouts is stored and is the only thing we overwrite from the original transaction + rawtx = node.createrawtransaction(inputs, outputs) + newtx = rawtx[0:92] + newtx = newtx + self.txouts + newtx = newtx + rawtx[94:] + # Appears to be ever so slightly faster to sign with SIGHASH_NONE + signresult = node.signrawtransaction(newtx,None,None,"NONE") + txid = node.sendrawtransaction(signresult["hex"], True) + # Mine a big sized block which will be these transactions we just created + node.generate(1) + + def run_test(self): + # Before we connect anything, we first set the time on the node + # to be in the past, otherwise things break because the CNode + # time counters can't be reset backward after initialization + + # set 2 weeks in the past + old_time = int(time.time() - 2*60*60*24*7) + self.nodes[0].setmocktime(old_time) + + # Generate some old blocks + # we scale this by EB + self.nodes[0].generate((130 * int(EXCESSIVE_BLOCKSIZE / 1000000))) + + # test_nodes[0] will only request old blocks + # test_nodes[1] will only request new blocks + # test_nodes[2] will test resetting the counters + test_nodes = [] + connections = [] + + for i in range(3): + test_nodes.append(TestNode()) + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_nodes[i])) + test_nodes[i].add_connection(connections[i]) + + NetworkThread().start() # Start up network handling in another thread + [x.wait_for_verack() for x in test_nodes] + + # Test logic begins here + + # Now mine a big block + self.mine_big_block(self.nodes[0], self.nodes[0].getnewaddress()) + + # Store the hash; we'll request this later + big_old_block = self.nodes[0].getbestblockhash() + old_block_size = self.nodes[0].getblock(big_old_block, True)['size'] + print ("mined big block size = %s bytes" % old_block_size) + big_old_block = int(big_old_block, 16) + + # Advance to two days ago + self.nodes[0].setmocktime(int(time.time()) - 2*60*60*24) + + # Mine one more block, so that the prior block looks old + self.mine_big_block(self.nodes[0], self.nodes[0].getnewaddress()) + + # We'll be requesting this new block too + big_new_block = self.nodes[0].getbestblockhash() + new_block_size = self.nodes[0].getblock(big_new_block)['size'] + big_new_block = int(big_new_block, 16) + + # test_nodes[0] will test what happens if we just keep requesting the + # the same big old block too many times (expect: disconnect) + + getdata_request = msg_getdata() + getdata_request.inv.append(CInv(2, big_old_block)) + + # Compute a theoretical amount of blocks that should be transferable + # based purely on the size of the big_old_block. + # This calculation will be inaccurate due to other protocol + # overheads, so a compensation factor is used later on to adjust + # for those. + successcount = int(self.max_bytes_available / old_block_size) + print("successcount = %s" % successcount) + compensation = int(successcount * (self.overhead_factor_a / 100.0)) + print("compensation = %s" % compensation) + + # 144MB will be reserved for relaying new blocks, so expect this to + # succeed for a certain number tries. + for i in range(successcount - compensation): + #print ("data request #%s" % (i+1)) + test_nodes[0].send_message(getdata_request) + test_nodes[0].sync_with_ping() + assert_equal(test_nodes[0].block_receive_map[big_old_block], i+1) + + # check that the node has not been disconnected yet + assert_equal(len(self.nodes[0].getpeerinfo()), 3) + print ("Peer 0 still connected after downloading old block %d times" % (successcount - compensation)) + + # At most a couple more tries should succeed (depending on how long + # the test has been running so far). + i = 1 + while True: + test_nodes[0].send_message(getdata_request) + test_nodes[0].sync_with_ping() + if test_nodes[0].peer_disconnected: break + i += 1 + + #for i in range(3 * compensation): + # test_nodes[0].send_message(getdata_request) + test_nodes[0].wait_for_disconnect() + assert_equal(len(self.nodes[0].getpeerinfo()), 2) + print("Peer 0 disconnected after downloading old block %d times" % (successcount - compensation + i)) + + # Requesting the current block on test_nodes[1] should succeed indefinitely, + # even when over the max upload target. + # We'll try 200 times + getdata_request.inv = [CInv(2, big_new_block)] + for i in range(200): + test_nodes[1].send_message(getdata_request) + test_nodes[1].sync_with_ping() + assert_equal(test_nodes[1].block_receive_map[big_new_block], i+1) + + print("Peer 1 able to repeatedly download new block") + + # But if test_nodes[1] tries for an old block, it gets disconnected too. + getdata_request.inv = [CInv(2, big_old_block)] + test_nodes[1].send_message(getdata_request) + test_nodes[1].wait_for_disconnect() + assert_equal(len(self.nodes[0].getpeerinfo()), 1) + + print("Peer 1 disconnected after trying to download old block") + + print("Advancing system time on node to clear counters...") + + # If we advance the time by 24 hours, then the counters should reset, + # and test_nodes[2] should be able to retrieve the old block. + self.nodes[0].setmocktime(int(time.time())) + test_nodes[2].sync_with_ping() + test_nodes[2].send_message(getdata_request) + test_nodes[2].sync_with_ping() + assert_equal(test_nodes[2].block_receive_map[big_old_block], 1) + + print("Peer 2 able to download old block") + + [c.disconnect_node() for c in connections] + + #stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1 + print("Restarting nodes with -whitelist=127.0.0.1") + stop_node(self.nodes[0], 0) + self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-use-thinblocks=0", "-whitelist=127.0.0.1", "-excessiveblocksize=1000000", "-maxuploadtarget=1", "-blockmaxsize=999000"]) + + #recreate/reconnect 3 test nodes + test_nodes = [] + connections = [] + + for i in range(3): + test_nodes.append(TestNode()) + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_nodes[i])) + test_nodes[i].add_connection(connections[i]) + + NetworkThread().start() # Start up network handling in another thread + [x.wait_for_verack() for x in test_nodes] + + #retrieve 20 blocks which should be enough to break the 1MB limit + getdata_request.inv = [CInv(2, big_new_block)] + for i in range(20): + test_nodes[1].send_message(getdata_request) + test_nodes[1].sync_with_ping() + assert_equal(test_nodes[1].block_receive_map[big_new_block], i+1) + + getdata_request.inv = [CInv(2, big_old_block)] + test_nodes[1].send_message(getdata_request) + test_nodes[1].wait_for_disconnect() + assert_equal(len(self.nodes[0].getpeerinfo()), 3) #node is still connected because of the whitelist + + print("Peer 1 still connected after trying to download old block (whitelisted)") + + [c.disconnect_node() for c in connections] + +if __name__ == '__main__': + MaxUploadTest().main() diff --git a/qa/rpc-tests/mempool_limit.py b/qa/rpc-tests/mempool_limit.py new file mode 100644 index 00000000..db2ab2a2 --- /dev/null +++ b/qa/rpc-tests/mempool_limit.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# Test mempool limiting together/eviction with the wallet + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class MempoolLimitTest(BitcoinTestFramework): + + def __init__(self): + self.txouts = gen_return_txouts() + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-maxmempool=5", "-spendzeroconfchange=0", "-debug"])) + self.is_network_split = False + self.sync_all() + self.relayfee = self.nodes[0].getnetworkinfo()['relayfee'] + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 2) + + def run_test(self): + txids = [] + utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], 90) + + #create a mempool tx that will be evicted + us0 = utxos.pop() + inputs = [{ "txid" : us0["txid"], "vout" : us0["vout"]}] + outputs = {self.nodes[0].getnewaddress() : 0.0001} + tx = self.nodes[0].createrawtransaction(inputs, outputs) + self.nodes[0].settxfee(self.relayfee) # specifically fund this tx with low fee + txF = self.nodes[0].fundrawtransaction(tx) + self.nodes[0].settxfee(0) # return to automatic fee selection + txFS = self.nodes[0].signrawtransaction(txF['hex']) + txid = self.nodes[0].sendrawtransaction(txFS['hex']) + + relayfee = self.nodes[0].getnetworkinfo()['relayfee'] + base_fee = relayfee*100 + for i in range (4): + txids.append([]) + txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[30*i:30*i+30], (i+1)*base_fee) + + # by now, the tx should be evicted, check confirmation state + assert(txid not in self.nodes[0].getrawmempool()) + txdata = self.nodes[0].gettransaction(txid) + assert(txdata['confirmations'] == 0) #confirmation should still be 0 + +if __name__ == '__main__': + MempoolLimitTest().main() diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py new file mode 100644 index 00000000..cb122d11 --- /dev/null +++ b/qa/rpc-tests/mempool_packages.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# Test descendant package tracking code + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.mininode import COIN + +MAX_ANCESTORS = 25 +MAX_DESCENDANTS = 25 + +class MempoolPackagesTest(BitcoinTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-relaypriority=0", "-debug"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-maxorphantx=1000", "-relaypriority=0", "-limitancestorcount=5", "-debug"])) + connect_nodes(self.nodes[0], 1) + self.is_network_split = False + self.sync_all() + + # Build a transaction that spends parent_txid:vout + # Return amount sent + def chain_transaction(self, node, parent_txid, vout, value, fee, num_outputs): + send_value = satoshi_round((value - fee)/num_outputs) + inputs = [ {'txid' : parent_txid, 'vout' : vout} ] + outputs = {} + for i in range(num_outputs): + outputs[node.getnewaddress()] = send_value + rawtx = node.createrawtransaction(inputs, outputs) + signedtx = node.signrawtransaction(rawtx) + txid = node.sendrawtransaction(signedtx['hex']) + fulltx = node.getrawtransaction(txid, 1) + assert(len(fulltx['vout']) == num_outputs) # make sure we didn't generate a change output + return (txid, send_value) + + def run_test(self): + ''' Mine some blocks and have them mature. ''' + self.nodes[0].generate(101) + utxo = self.nodes[0].listunspent(10) + txid = utxo[0]['txid'] + vout = utxo[0]['vout'] + value = utxo[0]['amount'] + + fee = Decimal("0.0001") + # MAX_ANCESTORS transactions off a confirmed tx should be fine + chain = [] + for i in range(MAX_ANCESTORS): + (txid, sent_value) = self.chain_transaction(self.nodes[0], txid, 0, value, fee, 1) + value = sent_value + chain.append(txid) + + # Check mempool has MAX_ANCESTORS transactions in it, and descendant + # count and fees should look correct + mempool = self.nodes[0].getrawmempool(True) + assert_equal(len(mempool), MAX_ANCESTORS) + descendant_count = 1 + descendant_fees = 0 + descendant_size = 0 + + 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'], descendant_fees * COIN) + descendant_size += mempool[x]['size'] + assert_equal(mempool[x]['descendantsize'], descendant_size) + descendant_count += 1 + + # Check that descendant modified fees includes fee deltas from + # prioritisetransaction + self.nodes[0].prioritisetransaction(chain[-1], 0, 1000) + mempool = self.nodes[0].getrawmempool(True) + + descendant_fees = 0 + for x in reversed(chain): + descendant_fees += mempool[x]['fee'] + assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 1000) + + # Adding one more transaction on to the chain should fail. + try: + self.chain_transaction(self.nodes[0], txid, vout, value, fee, 1) + except JSONRPCException as e: + print("too-long-ancestor-chain successfully rejected") + + # Check that prioritising a tx before it's added to the mempool works + # First clear the mempool by mining a block. + self.nodes[0].generate(1) + sync_blocks(self.nodes) + assert_equal(len(self.nodes[0].getrawmempool()), 0) + # Prioritise a transaction that has been mined, then add it back to the + # mempool by using invalidateblock. + self.nodes[0].prioritisetransaction(chain[-1], 0, 2000) + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + # Keep node1's tip synced with node0 + self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash()) + + # Now check that the transaction is in the mempool, with the right modified fee + mempool = self.nodes[0].getrawmempool(True) + + descendant_fees = 0 + for x in reversed(chain): + 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'], descendant_fees * COIN + 2000) + + # TODO: check that node1's mempool is as expected + + # TODO: test ancestor size limits + + # Now test descendant chain limits + txid = utxo[1]['txid'] + value = utxo[1]['amount'] + vout = utxo[1]['vout'] + + transaction_package = [] + # First create one parent tx with 10 children + (txid, sent_value) = self.chain_transaction(self.nodes[0], txid, vout, value, fee, 10) + parent_transaction = txid + for i in range(10): + transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value}) + + for i in range(MAX_DESCENDANTS): + utxo = transaction_package.pop(0) + try: + (txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10) + for j in range(10): + transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value}) + if i == MAX_DESCENDANTS - 2: + mempool = self.nodes[0].getrawmempool(True) + assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS) + except JSONRPCException as e: + print(e.error['message']) + assert_equal(i, MAX_DESCENDANTS - 1) + print("tx that would create too large descendant package successfully rejected") + + # TODO: check that node1's mempool is as expected + + # TODO: test descendant size limits + + # Test reorg handling + # First, the basics: + self.nodes[0].generate(1) + sync_blocks(self.nodes) + self.nodes[1].invalidateblock(self.nodes[0].getbestblockhash()) + self.nodes[1].reconsiderblock(self.nodes[0].getbestblockhash()) + + # Now test the case where node1 has a transaction T in its mempool that + # depends on transactions A and B which are in a mined block, and the + # block containing A and B is disconnected, AND B is not accepted back + # into node1's mempool because its ancestor count is too high. + + # Create 8 transactions, like so: + # Tx0 -> Tx1 (vout0) + # \--> Tx2 (vout1) -> Tx3 -> Tx4 -> Tx5 -> Tx6 -> Tx7 + # + # Mine them in the next block, then generate a new tx8 that spends + # Tx1 and Tx7, and add to node1's mempool, then disconnect the + # last block. + + # Create tx0 with 2 outputs + utxo = self.nodes[0].listunspent() + txid = utxo[0]['txid'] + value = utxo[0]['amount'] + vout = utxo[0]['vout'] + + send_value = satoshi_round((value - fee)/2) + inputs = [ {'txid' : txid, 'vout' : vout} ] + outputs = {} + for i in range(2): + outputs[self.nodes[0].getnewaddress()] = send_value + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + signedtx = self.nodes[0].signrawtransaction(rawtx) + txid = self.nodes[0].sendrawtransaction(signedtx['hex']) + tx0_id = txid + value = send_value + + # Create tx1 + (tx1_id, tx1_value) = self.chain_transaction(self.nodes[0], tx0_id, 0, value, fee, 1) + + # Create tx2-7 + vout = 1 + txid = tx0_id + for i in range(6): + (txid, sent_value) = self.chain_transaction(self.nodes[0], txid, vout, value, fee, 1) + vout = 0 + value = sent_value + + # Mine these in a block + self.nodes[0].generate(1) + self.sync_all() + + # Now generate tx8, with a big fee + inputs = [ {'txid' : tx1_id, 'vout': 0}, {'txid' : txid, 'vout': 0} ] + outputs = { self.nodes[0].getnewaddress() : send_value + value - 4*fee } + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + signedtx = self.nodes[0].signrawtransaction(rawtx) + txid = self.nodes[0].sendrawtransaction(signedtx['hex']) + sync_mempools(self.nodes) + + # Now try to disconnect the tip on each node... + self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash()) + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + sync_blocks(self.nodes) + +if __name__ == '__main__': + MempoolPackagesTest().main() diff --git a/qa/rpc-tests/mempool_reorg.py b/qa/rpc-tests/mempool_reorg.py new file mode 100644 index 00000000..91740cd9 --- /dev/null +++ b/qa/rpc-tests/mempool_reorg.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test re-org scenarios with a mempool that contains transactions +# that spend (directly or indirectly) coinbase transactions. +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +# Create one-input, one-output, no-fee transaction: +class MempoolCoinbaseTest(BitcoinTestFramework): + + alert_filename = None # Set by setup_network + + def setup_network(self): + args = ["-debug=mempool"] + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, args)) + self.nodes.append(start_node(1, self.options.tmpdir, args)) + connect_nodes(self.nodes[1], 0) + self.is_network_split = False + self.sync_all() + + def run_test(self): + start_count = self.nodes[0].getblockcount() + + # Mine three blocks. After this, nodes[0] blocks + # 101, 102, and 103 are spend-able. + new_blocks = self.nodes[1].generate(4) + self.sync_all() + node0_address = self.nodes[0].getnewaddress() + node1_address = self.nodes[1].getnewaddress() + + # Three scenarios for re-orging coinbase spends in the memory pool: + # 1. Direct coinbase spend : spend_101 + # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1 + # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1 + # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase), + # 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 = create_tx(self.nodes[0], coinbase_txids[1], node1_address, 50) + spend_102_raw = create_tx(self.nodes[0], coinbase_txids[2], node0_address, 50) + spend_103_raw = create_tx(self.nodes[0], coinbase_txids[3], node0_address, 50) + # 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: 50}) + # Set the time lock + timelock_tx = timelock_tx.replace("ffffffff", "11111111", 1) + timelock_tx = timelock_tx[:-8] + hex(self.nodes[0].getblockcount() + 2)[2:] + "000000" + timelock_tx = self.nodes[0].signrawtransaction(timelock_tx)["hex"] + assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx) + + # Broadcast and mine spend_102 and 103: + spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw) + spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw) + self.nodes[0].generate(1) + assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx) + self.sync_all() + + # Create 102_1 and 103_1: + spend_102_1_raw = create_tx(self.nodes[0], spend_102_id, node1_address, 50) + spend_103_1_raw = create_tx(self.nodes[0], spend_103_id, node1_address, 50) + + # Broadcast and mine 103_1: + spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw) + last_block = self.nodes[0].generate(1) + self.sync_all() + timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx) + self.sync_all() + + # ... now put spend_101 and spend_102_1 in memory pools: + spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw) + spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw) + self.sync_all() + + assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, timelock_tx_id}) + + for node in self.nodes: + node.invalidateblock(last_block[0]) + assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, spend_103_1_id}) + + # Use invalidateblock to re-org back and make all those coinbase spends + # immature/invalid: + for node in self.nodes: + node.invalidateblock(new_blocks[0]) + self.sync_all() + + # mempool should be empty. + assert_equal(set(self.nodes[0].getrawmempool()), set()) + +if __name__ == '__main__': + MempoolCoinbaseTest().main() diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py new file mode 100644 index 00000000..ad3b1c1e --- /dev/null +++ b/qa/rpc-tests/mempool_resurrect_test.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test resurrection of mined transactions when +# the blockchain is re-organized. +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +# Create one-input, one-output, no-fee transaction: +class MempoolCoinbaseTest(BitcoinTestFramework): + + def setup_network(self): + # Just need one node for this test + args = ["-debug=mempool"] + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, args)) + self.is_network_split = False + + def run_test(self): + node0_address = self.nodes[0].getnewaddress() + # Spend block 1/2/3's coinbase transactions + # Mine a block. + # Create three more transactions, spending the spends + # Mine another block. + # ... make sure all the transactions are confirmed + # Invalidate both blocks + # ... make sure all the transactions are put back in the mempool + # Mine a new block + # ... make sure all the transactions are confirmed again. + + 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 = [ create_tx(self.nodes[0], txid, node0_address, 50) 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 = [ create_tx(self.nodes[0], txid, node0_address, 49.99) for txid in spends1_id ] + spends2_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw ] + + blocks.extend(self.nodes[0].generate(1)) + + # mempool should be empty, all txns confirmed + assert_equal(set(self.nodes[0].getrawmempool()), set()) + for txid in spends1_id+spends2_id: + tx = self.nodes[0].gettransaction(txid) + assert(tx["confirmations"] > 0) + + # Use invalidateblock to re-org back; all transactions should + # end up unconfirmed and back in the mempool + for node in self.nodes: + node.invalidateblock(blocks[0]) + + # mempool should be empty, all txns confirmed + assert_equal(set(self.nodes[0].getrawmempool()), set(spends1_id+spends2_id)) + for txid in spends1_id+spends2_id: + tx = self.nodes[0].gettransaction(txid) + assert(tx["confirmations"] == 0) + + # Generate another block, they should all get mined + self.nodes[0].generate(1) + # mempool should be empty, all txns confirmed + assert_equal(set(self.nodes[0].getrawmempool()), set()) + for txid in spends1_id+spends2_id: + tx = self.nodes[0].gettransaction(txid) + assert(tx["confirmations"] > 0) + + +if __name__ == '__main__': + MempoolCoinbaseTest().main() diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py new file mode 100644 index 00000000..b98f1310 --- /dev/null +++ b/qa/rpc-tests/mempool_spendcoinbase.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test spending coinbase transactions. +# The coinbase transaction in block N can appear in block +# N+100... so is valid in the mempool when the best block +# height is N+99. +# This test makes sure coinbase spends that will be mature +# in the next block are accepted into the memory pool, +# but less mature coinbase spends are NOT. +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +# Create one-input, one-output, no-fee transaction: +class MempoolSpendCoinbaseTest(BitcoinTestFramework): + + def setup_network(self): + # Just need one node for this test + args = ["-debug=mempool"] + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, args)) + self.is_network_split = False + + def run_test(self): + chain_height = self.nodes[0].getblockcount() + assert_equal(chain_height, 200) + node0_address = self.nodes[0].getnewaddress() + + # Coinbase at height chain_height-100+1 ok in mempool, should + # get mined. Coinbase at height chain_height-100+2 is + # 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 = [ create_tx(self.nodes[0], txid, node0_address, 50) for txid in coinbase_txids ] + + spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0]) + + # coinbase at height 102 should be too immature to spend + assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, spends_raw[1]) + + # mempool should have just spend_101: + assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ]) + + # mine a block, spend_101 should get confirmed + self.nodes[0].generate(1) + assert_equal(set(self.nodes[0].getrawmempool()), set()) + + # ... and now height 102 can be spent: + spend_102_id = self.nodes[0].sendrawtransaction(spends_raw[1]) + assert_equal(self.nodes[0].getrawmempool(), [ spend_102_id ]) + +if __name__ == '__main__': + MempoolSpendCoinbaseTest().main() diff --git a/qa/rpc-tests/merkle_blocks.py b/qa/rpc-tests/merkle_blocks.py new file mode 100644 index 00000000..56941a98 --- /dev/null +++ b/qa/rpc-tests/merkle_blocks.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test merkleblock fetch/validation +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class MerkleBlockTest(BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self): + self.nodes = [] + # Nodes 0/1 are "wallet" nodes + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug"])) + # Nodes 2/3 are used for testing + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-txindex"])) + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[0], 2) + connect_nodes(self.nodes[0], 3) + + self.is_network_split = False + self.sync_all() + + def run_test(self): + print("Mining blocks...") + self.nodes[0].generate(105) + self.sync_all() + + chain_height = self.nodes[1].getblockcount() + assert_equal(chain_height, 105) + assert_equal(self.nodes[1].getbalance(), 0) + assert_equal(self.nodes[2].getbalance(), 0) + + node0utxos = self.nodes[0].listunspent(1) + tx1 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 50}) + txid1 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx1)["hex"]) + tx2 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 50}) + txid2 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx2)["hex"]) + assert_raises(JSONRPCException, self.nodes[0].gettxoutproof, [txid1]) + + self.nodes[0].generate(1) + blockhash = self.nodes[0].getblockhash(chain_height + 1) + self.sync_all() + + txlist = [] + blocktxn = self.nodes[0].getblock(blockhash, True)["tx"] + txlist.append(blocktxn[1]) + txlist.append(blocktxn[2]) + + assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1])), [txid1]) + assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2])), txlist) + assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2], blockhash)), txlist) + + txin_spent = self.nodes[1].listunspent(1).pop() + tx3 = self.nodes[1].createrawtransaction([txin_spent], {self.nodes[0].getnewaddress(): 50}) + self.nodes[0].sendrawtransaction(self.nodes[1].signrawtransaction(tx3)["hex"]) + self.nodes[0].generate(1) + self.sync_all() + + txid_spent = txin_spent["txid"] + txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2 + + # We can't find the block from a fully-spent tx + assert_raises(JSONRPCException, self.nodes[2].gettxoutproof, [txid_spent]) + # ...but we can if we specify the block + assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_spent], blockhash)), [txid_spent]) + # ...or if the first tx is not fully-spent + assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_unspent])), [txid_unspent]) + try: + assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2])), txlist) + except JSONRPCException: + assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid2, txid1])), txlist) + # ...or if we have a -txindex + assert_equal(self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof([txid_spent])), [txid_spent]) + +if __name__ == '__main__': + MerkleBlockTest().main() diff --git a/qa/rpc-tests/multi_rpc.py b/qa/rpc-tests/multi_rpc.py new file mode 100644 index 00000000..133d89ad --- /dev/null +++ b/qa/rpc-tests/multi_rpc.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test mulitple rpc user config option rpcauth +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +import http.client +import urllib.parse + +class HTTPBasicsTest (BitcoinTestFramework): + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir) + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain(self.options.tmpdir) + #Append rpcauth to bitcoin.conf before initialization + rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144" + rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e" + with open(os.path.join(self.options.tmpdir+"/node0", "bitcoin.conf"), 'a') as f: + f.write(rpcauth+"\n") + f.write(rpcauth2+"\n") + + def run_test(self): + + ################################################## + # Check correctness of the rpcauth config option # + ################################################## + url = urllib.parse.urlparse(self.nodes[0].url) + + #Old authpair + authpair = url.username + ':' + url.password + + #New authpair generated via share/rpcuser tool + rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144" + password = "cA773lm788buwYe4g4WT+05pKyNruVKjQ25x3n0DQcM=" + + #Second authpair with different username + rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e" + password2 = "8/F3uMDw4KSEbw96U3CA1C4X05dkHDN2BPFjTgZW4KI=" + authpairnew = "rt:"+password + + headers = {"Authorization": "Basic " + str_to_b64str(authpair)} + + conn = http.client.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, False) + conn.close() + + #Use new authpair to confirm both work + headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} + + conn = http.client.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, False) + conn.close() + + #Wrong login name with rt's password + authpairnew = "rtwrong:"+password + headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} + + conn = http.client.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, True) + conn.close() + + #Wrong password for rt + authpairnew = "rt:"+password+"wrong" + headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} + + conn = http.client.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, True) + conn.close() + + #Correct for rt2 + authpairnew = "rt2:"+password2 + headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} + + conn = http.client.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, False) + conn.close() + + #Wrong password for rt2 + authpairnew = "rt2:"+password2+"wrong" + headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} + + conn = http.client.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, True) + conn.close() + + +if __name__ == '__main__': + HTTPBasicsTest ().main () diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py new file mode 100644 index 00000000..b5013b0a --- /dev/null +++ b/qa/rpc-tests/nodehandling.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test node handling +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +import http.client +import urllib.parse + +class NodeHandlingTest (BitcoinTestFramework): + def run_test(self): + ########################### + # setban/listbanned tests # + ########################### + assert_equal(len(self.nodes[2].getpeerinfo()), 4) #we should have 4 nodes at this point + self.nodes[2].setban("127.0.0.1", "add") + time.sleep(3) #wait till the nodes are disconected + assert_equal(len(self.nodes[2].getpeerinfo()), 0) #all nodes must be disconnected at this point + assert_equal(len(self.nodes[2].listbanned()), 1) + self.nodes[2].clearbanned() + assert_equal(len(self.nodes[2].listbanned()), 0) + self.nodes[2].setban("127.0.0.0/24", "add") + assert_equal(len(self.nodes[2].listbanned()), 1) + try: + self.nodes[2].setban("127.0.0.1", "add") #throws exception because 127.0.0.1 is within range 127.0.0.0/24 + except: + pass + assert_equal(len(self.nodes[2].listbanned()), 1) #still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 + try: + self.nodes[2].setban("127.0.0.1", "remove") + except: + pass + assert_equal(len(self.nodes[2].listbanned()), 1) + self.nodes[2].setban("127.0.0.0/24", "remove") + assert_equal(len(self.nodes[2].listbanned()), 0) + self.nodes[2].clearbanned() + assert_equal(len(self.nodes[2].listbanned()), 0) + + ##test persisted banlist + self.nodes[2].setban("127.0.0.0/32", "add") + self.nodes[2].setban("127.0.0.0/24", "add") + self.nodes[2].setban("192.168.0.1", "add", 1) #ban for 1 seconds + self.nodes[2].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) #ban for 1000 seconds + listBeforeShutdown = self.nodes[2].listbanned() + assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) #must be here + time.sleep(2) #make 100% sure we expired 192.168.0.1 node time + + #stop node + stop_node(self.nodes[2], 2) + + self.nodes[2] = start_node(2, self.options.tmpdir) + listAfterShutdown = self.nodes[2].listbanned() + assert_equal("127.0.0.0/24", listAfterShutdown[0]['address']) + assert_equal("127.0.0.0/32", listAfterShutdown[1]['address']) + assert_equal("/19" in listAfterShutdown[2]['address'], True) + + ########################### + # RPC disconnectnode test # + ########################### + url = urllib.parse.urlparse(self.nodes[1].url) + self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1))) + time.sleep(2) #disconnecting a node needs a little bit of time + for node in self.nodes[0].getpeerinfo(): + assert(node['addr'] != url.hostname+":"+str(p2p_port(1))) + + connect_nodes_bi(self.nodes,0,1) #reconnect the node + found = False + for node in self.nodes[0].getpeerinfo(): + if node['addr'] == url.hostname+":"+str(p2p_port(1)): + found = True + assert(found) + +if __name__ == '__main__': + NodeHandlingTest ().main () diff --git a/qa/rpc-tests/p2p-acceptblock.py b/qa/rpc-tests/p2p-acceptblock.py new file mode 100644 index 00000000..e66a6eea --- /dev/null +++ b/qa/rpc-tests/p2p-acceptblock.py @@ -0,0 +1,296 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.mininode import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import time +from test_framework.blocktools import create_block, create_coinbase + +''' +AcceptBlockTest -- test processing of unrequested blocks. + +Since behavior differs when receiving unrequested blocks from whitelisted peers +versus non-whitelisted peers, this tests the behavior of both (effectively two +separate tests running in parallel). + +Setup: two nodes, node0 and node1, not connected to each other. Node0 does not +whitelist localhost, but node1 does. They will each be on their own chain for +this test. + +We have one NodeConn connection to each, test_node and white_node respectively. + +The test: +1. Generate one block on each node, to leave IBD. + +2. Mine a new block on each tip, and deliver to each node from node's peer. + The tip should advance. + +3. Mine a block that forks the previous block, and deliver to each node from + corresponding peer. + Node0 should not process this block (just accept the header), because it is + unrequested and doesn't have more work than the tip. + Node1 should process because this is coming from a whitelisted peer. + +4. Send another block that builds on the forking block. + Node0 should process this block but be stuck on the shorter chain, because + it's missing an intermediate block. + Node1 should reorg to this longer chain. + +4b.Send 288 more blocks on the longer chain. + Node0 should process all but the last block (too far ahead in height). + Send all headers to Node1, and then send the last block in that chain. + Node1 should accept the block because it's coming from a whitelisted peer. + +5. Send a duplicate of the block in #3 to Node0. + Node0 should not process the block because it is unrequested, and stay on + the shorter chain. + +6. Send Node0 an inv for the height 3 block produced in #4 above. + Node0 should figure out that Node0 has the missing height 2 block and send a + getdata. + +7. Send Node0 the missing block again. + Node0 should process and the tip should advance. +''' + +# 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 + + # Track the last getdata message we receive (used in the test) + def on_getdata(self, conn, message): + self.last_getdata = message + + # Spin until verack message is received from the node. + # We use this to signal that our test can begin. This + # is called from the testing thread, so it needs to acquire + # the global lock. + def wait_for_verack(self): + while True: + with mininode_lock: + if self.verack_received: + return + time.sleep(0.05) + + # 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 AcceptBlockTest(BitcoinTestFramework): + def add_options(self, parser): + parser.add_option("--testbinary", dest="testbinary", + default=os.getenv("BITCOIND", "bitcoind"), + help="bitcoind binary to test") + + def setup_chain(self): + initialize_chain_clean(self.options.tmpdir, 2) + + def setup_network(self): + # Node0 will be used to test behavior of processing unrequested blocks + # from peers which are not whitelisted, while Node1 will be used for + # the whitelisted case. + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"], + binary=self.options.testbinary)) + self.nodes.append(start_node(1, self.options.tmpdir, + ["-debug", "-whitelist=127.0.0.1"], + binary=self.options.testbinary)) + + def run_test(self): + # Setup the p2p connections and start up the network thread. + test_node = TestNode() # connects to node0 (not whitelisted) + white_node = TestNode() # connects to node1 (whitelisted) + + connections = [] + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node)) + connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], white_node)) + test_node.add_connection(connections[0]) + white_node.add_connection(connections[1]) + + NetworkThread().start() # Start up network handling in another thread + + # Test logic begins here + test_node.wait_for_verack() + white_node.wait_for_verack() + + # 1. Have both nodes mine a block (leave IBD) + [ n.generate(1) for n in self.nodes ] + tips = [ int("0x" + n.getbestblockhash(), 0) for n in self.nodes ] + + # 2. Send one block that builds on each tip. + # This should be accepted. + blocks_h2 = [] # the height 2 blocks on each node's chain + block_time = int(time.time()) + 1 + for i in range(2): + blocks_h2.append(create_block(tips[i], create_coinbase(2), block_time)) + blocks_h2[i].solve() + block_time += 1 + test_node.send_message(msg_block(blocks_h2[0])) + white_node.send_message(msg_block(blocks_h2[1])) + + [ x.sync_with_ping() for x in [test_node, white_node] ] + assert_equal(self.nodes[0].getblockcount(), 2) + assert_equal(self.nodes[1].getblockcount(), 2) + print("First height 2 block accepted by both nodes") + + # 3. Send another block that builds on the original tip. + blocks_h2f = [] # Blocks at height 2 that fork off the main chain + for i in range(2): + blocks_h2f.append(create_block(tips[i], create_coinbase(2), blocks_h2[i].nTime+1)) + blocks_h2f[i].solve() + test_node.send_message(msg_block(blocks_h2f[0])) + white_node.send_message(msg_block(blocks_h2f[1])) + + [ x.sync_with_ping() for x in [test_node, white_node] ] + for x in self.nodes[0].getchaintips(): + if x['hash'] == blocks_h2f[0].hash: + assert_equal(x['status'], "headers-only") + + for x in self.nodes[1].getchaintips(): + if x['hash'] == blocks_h2f[1].hash: + assert_equal(x['status'], "valid-headers") + + print("Second height 2 block accepted only from whitelisted peer") + + # 4. Now send another block that builds on the forking chain. + blocks_h3 = [] + for i in range(2): + blocks_h3.append(create_block(blocks_h2f[i].sha256, create_coinbase(3), blocks_h2f[i].nTime+1)) + blocks_h3[i].solve() + test_node.send_message(msg_block(blocks_h3[0])) + white_node.send_message(msg_block(blocks_h3[1])) + + [ x.sync_with_ping() for x in [test_node, white_node] ] + # Since the earlier block was not processed by node0, the new block + # can't be fully validated. + for x in self.nodes[0].getchaintips(): + if x['hash'] == blocks_h3[0].hash: + assert_equal(x['status'], "headers-only") + + # But this block should be accepted by node0 since it has more work. + try: + self.nodes[0].getblock(blocks_h3[0].hash) + print("Unrequested more-work block accepted from non-whitelisted peer") + except: + raise AssertionError("Unrequested more work block was not processed") + + # Node1 should have accepted and reorged. + assert_equal(self.nodes[1].getblockcount(), 3) + print("Successfully reorged to length 3 chain from whitelisted peer") + + # 4b. Now mine 288 more blocks and deliver; all should be processed but + # the last (height-too-high) on node0. Node1 should process the tip if + # we give it the headers chain leading to the tip. + tips = blocks_h3 + headers_message = msg_headers() + all_blocks = [] # node0's blocks + for j in range(2): + for i in range(288): + next_block = create_block(tips[j].sha256, create_coinbase(i + 4), tips[j].nTime+1) + next_block.solve() + if j==0: + test_node.send_message(msg_block(next_block)) + all_blocks.append(next_block) + else: + headers_message.headers.append(CBlockHeader(next_block)) + tips[j] = next_block + test_node.sync_with_ping() + time.sleep(2) + for x in all_blocks: + try: + self.nodes[0].getblock(x.hash) + if x == all_blocks[287]: + raise AssertionError("Unrequested block too far-ahead should have been ignored") + except: + if x == all_blocks[287]: + print("Unrequested block too far-ahead not processed") + else: + raise AssertionError("Unrequested block with more work should have been accepted") + + headers_message.headers.pop() # Ensure the last block is unrequested + white_node.send_message(headers_message) # Send headers leading to tip + white_node.send_message(msg_block(tips[1])) # Now deliver the tip + try: + white_node.sync_with_ping() + self.nodes[1].getblock(tips[1].hash) + print("Unrequested block far ahead of tip accepted from whitelisted peer") + except: + raise AssertionError("Unrequested block from whitelisted peer not accepted") + + # 5. Test handling of unrequested block on the node that didn't process + # Should still not be processed (even though it has a child that has more + # work). + test_node.send_message(msg_block(blocks_h2f[0])) + + # Here, if the sleep is too short, the test could falsely succeed (if the + # node hasn't processed the block by the time the sleep returns, and then + # the node processes it and incorrectly advances the tip). + # But this would be caught later on, when we verify that an inv triggers + # a getdata request for this block. + test_node.sync_with_ping() + assert_equal(self.nodes[0].getblockcount(), 2) + print("Unrequested block that would complete more-work chain was ignored") + + # 6. Try to get node to request the missing block. + # Poke the node with an inv for block at height 3 and see if that + # triggers a getdata on block 2 (it should if block 2 is missing). + with mininode_lock: + # Clear state so we can check the getdata request + test_node.last_getdata = None + test_node.send_message(msg_inv([CInv(2, blocks_h3[0].sha256)])) + + test_node.sync_with_ping() + with mininode_lock: + getdata = test_node.last_getdata + + # Check that the getdata includes the right block + assert_equal(getdata.inv[0].hash, blocks_h2f[0].sha256) + print("Inv at tip triggered getdata for unprocessed block") + + # 7. Send the missing block for the third time (now it is requested) + test_node.send_message(msg_block(blocks_h2f[0])) + test_node.sync_with_ping() + + # Wait for the reorg to complete. It can be slower on some systems. + while self.nodes[0].getblockcount() != 290: + time.sleep(1) + j = j + 1 + if (j > 60): + break + + assert_equal(self.nodes[0].getblockcount(), 290) + print("Successfully reorged to longer chain from non-whitelisted peer") + + [ c.disconnect_node() for c in connections ] + +if __name__ == '__main__': + AcceptBlockTest().main() diff --git a/qa/rpc-tests/p2p-fullblocktest.py b/qa/rpc-tests/p2p-fullblocktest.py new file mode 100644 index 00000000..56df8ffd --- /dev/null +++ b/qa/rpc-tests/p2p-fullblocktest.py @@ -0,0 +1,399 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import ComparisonTestFramework +from test_framework.util import * +from test_framework.comptool import TestManager, TestInstance, RejectResult +from test_framework.blocktools import * +import time +from test_framework.key import CECKey +from test_framework.script import CScript, SignatureHash, SIGHASH_ALL, OP_TRUE, OP_FALSE + +class PreviousSpendableOutput(object): + def __init__(self, tx = CTransaction(), n = -1): + self.tx = tx + self.n = n # the output we're spending + +''' +This reimplements tests from the bitcoinj/FullBlockTestGenerator used +by the pull-tester. + +We use the testing framework in which we expect a particular answer from +each test. +''' + +class FullBlockTest(ComparisonTestFramework): + + ''' Can either run this test as 1 node with expected answers, or two and compare them. + Change the "outcome" variable from each TestInstance object to only do the comparison. ''' + def __init__(self): + self.num_nodes = 1 + self.block_heights = {} + self.coinbase_key = CECKey() + self.coinbase_key.set_secretbytes(b"horsebattery") + self.coinbase_pubkey = self.coinbase_key.get_pubkey() + self.block_time = int(time.time())+1 + self.tip = None + self.blocks = {} + + def run_test(self): + test = TestManager(self, self.options.tmpdir) + test.add_all_connections(self.nodes) + NetworkThread().start() # Start up network handling in another thread + test.run() + + def add_transactions_to_block(self, block, tx_list): + [ tx.rehash() for tx in tx_list ] + block.vtx.extend(tx_list) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + return block + + # Create a block on top of self.tip, and advance self.tip to point to the new block + # if spend is specified, then 1 satoshi will be spent from that to an anyone-can-spend output, + # and rest will go to fees. + def next_block(self, number, spend=None, additional_coinbase_value=0, script=None): + if self.tip == None: + base_block_hash = self.genesis_hash + else: + base_block_hash = self.tip.sha256 + # First create the coinbase + height = self.block_heights[base_block_hash] + 1 + coinbase = create_coinbase(height, self.coinbase_pubkey) + coinbase.vout[0].nValue += additional_coinbase_value + if (spend != None): + coinbase.vout[0].nValue += spend.tx.vout[spend.n].nValue - 1 # all but one satoshi to fees + coinbase.rehash() + block = create_block(base_block_hash, coinbase, self.block_time) + if (spend != None): + tx = CTransaction() + tx.vin.append(CTxIn(COutPoint(spend.tx.sha256, spend.n), b"", 0xffffffff)) # no signature yet + # This copies the java comparison tool testing behavior: the first + # txout has a garbage scriptPubKey, "to make sure we're not + # pre-verifying too much" (?) + tx.vout.append(CTxOut(0, CScript([random.randint(0,255), height & 255]))) + if script == None: + tx.vout.append(CTxOut(1, CScript([OP_TRUE]))) + else: + tx.vout.append(CTxOut(1, script)) + # Now sign it if necessary + scriptSig = b"" + scriptPubKey = bytearray(spend.tx.vout[spend.n].scriptPubKey) + if (scriptPubKey[0] == OP_TRUE): # looks like an anyone-can-spend + scriptSig = CScript([OP_TRUE]) + else: + # We have to actually sign it + (sighash, err) = SignatureHash(spend.tx.vout[spend.n].scriptPubKey, tx, 0, SIGHASH_ALL) + scriptSig = CScript([self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))]) + tx.vin[0].scriptSig = scriptSig + # Now add the transaction to the block + block = self.add_transactions_to_block(block, [tx]) + block.solve() + self.tip = block + self.block_heights[block.sha256] = height + self.block_time += 1 + assert number not in self.blocks + self.blocks[number] = block + return block + + def get_tests(self): + self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16) + self.block_heights[self.genesis_hash] = 0 + spendable_outputs = [] + + # save the current tip so it can be spent by a later block + def save_spendable_output(): + spendable_outputs.append(self.tip) + + # get an output that we previous marked as spendable + def get_spendable_output(): + return PreviousSpendableOutput(spendable_outputs.pop(0).vtx[0], 0) + + # returns a test case that asserts that the current tip was accepted + def accepted(): + return TestInstance([[self.tip, True]]) + + # returns a test case that asserts that the current tip was rejected + def rejected(reject = None): + if reject is None: + return TestInstance([[self.tip, False]]) + else: + return TestInstance([[self.tip, reject]]) + + # move the tip back to a previous block + def tip(number): + self.tip = self.blocks[number] + + # add transactions to a block produced by next_block + def update_block(block_number, new_transactions): + block = self.blocks[block_number] + old_hash = block.sha256 + self.add_transactions_to_block(block, new_transactions) + block.solve() + # Update the internal state just like in next_block + self.tip = block + self.block_heights[block.sha256] = self.block_heights[old_hash] + del self.block_heights[old_hash] + self.blocks[block_number] = block + return block + + # creates a new block and advances the tip to that block + block = self.next_block + + + # Create a new block + block(0) + save_spendable_output() + yield accepted() + + + # Now we need that block to mature so we can spend the coinbase. + test = TestInstance(sync_every_block=False) + for i in range(99): + block(1000 + i) + test.blocks_and_transactions.append([self.tip, True]) + save_spendable_output() + yield test + + + # Start by building a couple of blocks on top (which output is spent is + # in parentheses): + # genesis -> b1 (0) -> b2 (1) + out0 = get_spendable_output() + block(1, spend=out0) + save_spendable_output() + yield accepted() + + out1 = get_spendable_output() + b2 = block(2, spend=out1) + yield accepted() + + + # so fork like this: + # + # genesis -> b1 (0) -> b2 (1) + # \-> b3 (1) + # + # Nothing should happen at this point. We saw b2 first so it takes priority. + tip(1) + b3 = block(3, spend=out1) + txout_b3 = PreviousSpendableOutput(b3.vtx[1], 1) + yield rejected() + + + # Now we add another block to make the alternative chain longer. + # + # genesis -> b1 (0) -> b2 (1) + # \-> b3 (1) -> b4 (2) + out2 = get_spendable_output() + block(4, spend=out2) + yield accepted() + + + # ... and back to the first chain. + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b3 (1) -> b4 (2) + tip(2) + block(5, spend=out2) + save_spendable_output() + yield rejected() + + out3 = get_spendable_output() + block(6, spend=out3) + yield accepted() + + + # Try to create a fork that double-spends + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b7 (2) -> b8 (4) + # \-> b3 (1) -> b4 (2) + tip(5) + block(7, spend=out2) + yield rejected() + + out4 = get_spendable_output() + block(8, spend=out4) + yield rejected() + + + # Try to create a block that has too much fee + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b9 (4) + # \-> b3 (1) -> b4 (2) + tip(6) + block(9, spend=out4, additional_coinbase_value=1) + yield rejected(RejectResult(16, b'bad-cb-amount')) + + + # Create a fork that ends in a block with too much fee (the one that causes the reorg) + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b10 (3) -> b11 (4) + # \-> b3 (1) -> b4 (2) + tip(5) + block(10, spend=out3) + yield rejected() + + block(11, spend=out4, additional_coinbase_value=1) + yield rejected(RejectResult(16, b'bad-cb-amount')) + + + # Try again, but with a valid fork first + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b14 (5) + # (b12 added last) + # \-> b3 (1) -> b4 (2) + tip(5) + b12 = block(12, spend=out3) + save_spendable_output() + #yield TestInstance([[b12, False]]) + b13 = block(13, spend=out4) + # Deliver the block header for b12, and the block b13. + # b13 should be accepted but the tip won't advance until b12 is delivered. + yield TestInstance([[CBlockHeader(b12), None], [b13, False]]) + + save_spendable_output() + out5 = get_spendable_output() + # b14 is invalid, but the node won't know that until it tries to connect + # Tip still can't advance because b12 is missing + block(14, spend=out5, additional_coinbase_value=1) + yield rejected() + + yield TestInstance([[b12, True, b13.sha256]]) # New tip should be b13. + + # Add a block with MAX_BLOCK_SIGOPS and one with one more sigop + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) -> b16 (6) + # \-> b3 (1) -> b4 (2) + + # Test that a block with a lot of checksigs is okay + lots_of_checksigs = CScript([OP_CHECKSIG] * (1000000 // 50 - 1)) + tip(13) + block(15, spend=out5, script=lots_of_checksigs) + yield accepted() + + + # Test that a block with too many checksigs is rejected + out6 = get_spendable_output() + too_many_checksigs = CScript([OP_CHECKSIG] * (1000000 // 50)) + block(16, spend=out6, script=too_many_checksigs) + yield rejected(RejectResult(16, b'bad-blk-sigops')) + + + # Attempt to spend a transaction created on a different fork + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) -> b17 (b3.vtx[1]) + # \-> b3 (1) -> b4 (2) + tip(15) + block(17, spend=txout_b3) + yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) + + # Attempt to spend a transaction created on a different fork (on a fork this time) + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) + # \-> b18 (b3.vtx[1]) -> b19 (6) + # \-> b3 (1) -> b4 (2) + tip(13) + block(18, spend=txout_b3) + yield rejected() + + block(19, spend=out6) + yield rejected() + + # Attempt to spend a coinbase at depth too low + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) -> b20 (7) + # \-> b3 (1) -> b4 (2) + tip(15) + out7 = get_spendable_output() + block(20, spend=out7) + yield rejected(RejectResult(16, b'bad-txns-premature-spend-of-coinbase')) + + # Attempt to spend a coinbase at depth too low (on a fork this time) + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) + # \-> b21 (6) -> b22 (5) + # \-> b3 (1) -> b4 (2) + tip(13) + block(21, spend=out6) + yield rejected() + + block(22, spend=out5) + yield rejected() + + # Create a block on either side of MAX_BLOCK_SIZE and make sure its accepted/rejected + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) + # \-> b24 (6) -> b25 (7) + # \-> b3 (1) -> b4 (2) + tip(15) + b23 = block(23, spend=out6) + old_hash = b23.sha256 + tx = CTransaction() + script_length = MAX_BLOCK_SIZE - len(b23.serialize()) - 69 + script_output = CScript([b'\x00' * script_length]) + tx.vout.append(CTxOut(0, script_output)) + tx.vin.append(CTxIn(COutPoint(b23.vtx[1].sha256, 1))) + b23 = update_block(23, [tx]) + # Make sure the math above worked out to produce a max-sized block + assert_equal(len(b23.serialize()), MAX_BLOCK_SIZE) + yield accepted() + + # Make the next block one byte bigger and check that it fails + tip(15) + b24 = block(24, spend=out6) + script_length = MAX_BLOCK_SIZE - len(b24.serialize()) - 69 + script_output = CScript([b'\x00' * (script_length+1)]) + tx.vout = [CTxOut(0, script_output)] + b24 = update_block(24, [tx]) + assert_equal(len(b24.serialize()), MAX_BLOCK_SIZE+1) + yield rejected(RejectResult(16, b'bad-blk-length')) + + b25 = block(25, spend=out7) + yield rejected() + + # Create blocks with a coinbase input script size out of range + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7) + # \-> ... (6) -> ... (7) + # \-> b3 (1) -> b4 (2) + tip(15) + b26 = block(26, spend=out6) + b26.vtx[0].vin[0].scriptSig = b'\x00' + b26.vtx[0].rehash() + # update_block causes the merkle root to get updated, even with no new + # transactions, and updates the required state. + b26 = update_block(26, []) + yield rejected(RejectResult(16, b'bad-cb-length')) + + # Extend the b26 chain to make sure bitcoind isn't accepting b26 + b27 = block(27, spend=out7) + yield rejected() + + # Now try a too-large-coinbase script + tip(15) + b28 = block(28, spend=out6) + b28.vtx[0].vin[0].scriptSig = b'\x00' * 101 + b28.vtx[0].rehash() + b28 = update_block(28, []) + yield rejected(RejectResult(16, b'bad-cb-length')) + + # Extend the b28 chain to make sure bitcoind isn't accepted b28 + b29 = block(29, spend=out7) + # TODO: Should get a reject message back with "bad-prevblk", except + # there's a bug that prevents this from being detected. Just note + # failure for now, and add the reject result later. + yield rejected() + + # b30 has a max-sized coinbase scriptSig. + tip(23) + b30 = block(30) + b30.vtx[0].vin[0].scriptSig = b'\x00' * 100 + b30.vtx[0].rehash() + b30 = update_block(30, []) + yield accepted() + + +if __name__ == '__main__': + FullBlockTest().main() diff --git a/qa/rpc-tests/p2p-versionbits-warning.py b/qa/rpc-tests/p2p-versionbits-warning.py new file mode 100644 index 00000000..0a274dbf --- /dev/null +++ b/qa/rpc-tests/p2p-versionbits-warning.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 +# Copyright (c) 2016 The Bitcoin Core developers +# Copyright (c) 2016-2017 The Bitcoin Unlimited 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", "-whitelist=127.0.0.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 range(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) + assert(self.nodes[0].getblockcount() == 144) + + # 2. Now build one period of blocks on the tip, with < VB_THRESHOLD + # blocks signaling some unknown bit. + nVersion = VB_TOP_BITS | (1<= VB_THRESHOLD blocks signaling + # some unknown bit + for i in range(VB_THRESHOLD): + self.send_blocks_with_version(test_node, 1, nVersion) + test_node.sync_with_ping() + # time.sleep(0.05) + assert(self.nodes[0].getblockcount() == 396) + 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) + assert(self.nodes[0].getblockcount() == 432) + + # 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) + assert(self.nodes[0].getblockcount() == 577) + 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/parallel.py b/qa/rpc-tests/parallel.py new file mode 100644 index 00000000..2460753a --- /dev/null +++ b/qa/rpc-tests/parallel.py @@ -0,0 +1,1139 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2016 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class ParallelTest (BitcoinTestFramework): + def __init__(self): + self.rep = False + BitcoinTestFramework.__init__(self) + + def setup_chain(self): + print ("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 6) + + def setup_network(self, split=False): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-parallel=0", "-rpcservertimeout=0", "-debug", "-use-thinblocks=0", "-excessiveblocksize=6000000", "-blockprioritysize=6000000", "-blockmaxsize=6000000"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-parallel=0", "-rpcservertimeout=0", "-debug", "-use-thinblocks=0", "-excessiveblocksize=6000000", "-blockprioritysize=6000000", "-blockmaxsize=6000000"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-parallel=0", "-rpcservertimeout=0", "-debug", "-use-thinblocks=0", "-excessiveblocksize=6000000", "-blockprioritysize=6000000", "-blockmaxsize=6000000"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-parallel=0", "-rpcservertimeout=0", "-debug", "-use-thinblocks=0", "-excessiveblocksize=6000000", "-blockprioritysize=6000000", "-blockmaxsize=6000000"])) + interconnect_nodes(self.nodes) + self.is_network_split=False + self.sync_all() + + def cleanup_and_reset(self): + + # Cleanup - start and connect the other nodes so that we have syncd chains before proceeding + # to other tests. + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug=", "-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug=", "-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug=", "-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug=", "-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug=", "-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug=", "-pvtest=0", "-whitelist=127.0.0.1"])) + interconnect_nodes(self.nodes) + sync_blocks(self.nodes) + + print ("Mine more blocks on each node...") + self.nodes[0].generate(25) + sync_blocks(self.nodes) + self.nodes[1].generate(25) + sync_blocks(self.nodes) + self.nodes[2].generate(25) + sync_blocks(self.nodes) + self.nodes[3].generate(25) + sync_blocks(self.nodes) + self.nodes[4].generate(25) + sync_blocks(self.nodes) + self.nodes[5].generate(25) + sync_blocks(self.nodes) + + stop_nodes(self.nodes) + wait_bitcoinds() + + def repetitiveTest(self): + # get some coins + self.nodeLookup = {} + i = 0 + for n in self.nodes: + print("Node %d is %s" % (i,n.url)) + print ("generating coins for node") + n.generate(200) + self.sync_all() + i += 1 + + for i in range(0,200): + # Create many utxo's + print ("round %d: Generating txns..." % i) + for n in self.nodes: + send_to = {} + n.keypoolrefill(100) + n.keypoolrefill(100) + for i in range(200): + send_to[n.getnewaddress()] = Decimal("0.01") + n.sendmany("", send_to) + + self.sync_all() + print (" generating blocks...") + i = 0 + for n in self.nodes: + try: + n.generate(1) + except JSONRPCException as e: + print (e) + print ("Node ", i, " ", n.url) + pdb.set_trace() + i += 1 + print (" syncing...") + self.sync_all() + + def run_test (self): + if self.rep: + self.repetitiveTest() + return + + print ("Mining blocks with PV off...") + # Mine some blocks on node2 which we will need at the end to generate a few transactions from that node + # in order to create the small block with just a few transactions in it. + self.nodes[2].generate(2) + self.sync_all() + + # Mine the rest on node0 where we will generate the bigger block. + self.nodes[0].generate(100) + self.sync_all() + + self.nodes[0].generate(1) + self.sync_all() + + self.nodes[2].generate(100) + self.sync_all() + + + #stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + #restart nodes with -pvtest off and do not yet connect the nodes + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + + # Send tx's which do not propagate + for i in range(50): + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.01") + + # Send a few transactions from node2 that will get mined so that we will have at least + # a few inputs to check when the two competing blocks enter parallel validation. + for i in range(5): + self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), "0.01") + + + # Have node0 and node2 mine the same block which will compete to advance the chaintip when + # The nodes are connected back together. + print ("Mine two competing blocks...") + self.nodes[0].generate(1) + self.nodes[2].generate(1) + + #stop nodes and restart right away + stop_nodes(self.nodes) + wait_bitcoinds() + + # Restart nodes with pvtest=1 + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=1"])) + + print ("Connect nodes...") + interconnect_nodes(self.nodes) + sync_blocks(self.nodes[0:3]) + + # Wait here to make sure a re-org does not happen on node0 so we want to give it some time. If the + # memory pool on node 0 does not change within 5 seconds then we assume a reorg is not occurring + # because a reorg would cause transactions to be placed in the mempool from the old block on node 0. + old_mempoolbytes = self.nodes[0].getmempoolinfo()["bytes"] + for i in range(5): + mempoolbytes = self.nodes[0].getmempoolinfo()["bytes"] + if old_mempoolbytes != mempoolbytes: + assert("Reorg happened when it should not - Mempoolbytes has changed") + old_mempoolbytes = mempoolbytes + # node0 has the bigger block and was sent and began processing first, however the block from node2 + # should have come in after and beaten node0's block. Therefore the blockhash from chaintip from + # node2 should now match the blockhash from the chaintip on node1; and node0 and node1 should not match. + print ("check for re-org " + str(i+1)) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash()) + assert_not_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash()) + time.sleep(1) + + #stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + # Restart nodes with pvtest off. + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + + print ("Connect nodes...") + interconnect_nodes(self.nodes) + + # mine a block on node3 and then connect to the others. This tests when a third block arrives after + # the tip has been advanced. + # this block should propagate to the other nodes but not cause a re-org + print ("Mine another block...") + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes[3].generate(1) + connect_nodes(self.nodes[1],3) + sync_blocks(self.nodes) + + # Wait here to make sure a re-org does not happen on node0 so we want to give it some time. If the + # memory pool on node 0 does not change within 5 seconds then we assume a reorg is not occurring + # because a reorg would cause transactions to be placed in the mempool from the old block on node 0. + for i in range(5): + mempoolbytes = self.nodes[0].getmempoolinfo()["bytes"] + if old_mempoolbytes != mempoolbytes: + assert("Reorg happened when it should not - Mempoolbytes has changed") + old_mempoolbytes = mempoolbytes + print ("check for re-org " + str(i+1)) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash()) + assert_not_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash()) + assert_not_equal(self.nodes[1].getbestblockhash(), self.nodes[3].getbestblockhash()) + time.sleep(1) + + + # Send some transactions and Mine a block on node 2. + # This should cause node0 and node3 to re-org and all chains should now match. + for i in range(5): + self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(), .01) + print ("Mine another block on node2 which causes a reorg on node0 and node3...") + self.nodes[2].generate(1) + sync_blocks(self.nodes) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash()) + assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash()) + counts = [ x.getblockcount() for x in self.nodes ] + assert_equal(counts, [205,205,205,205]) + + #stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=0"])) + connect_nodes(self.nodes[1],0) + connect_nodes(self.nodes[1],2) + connect_nodes(self.nodes[1],3) + connect_nodes(self.nodes[1],4) + connect_nodes(self.nodes[1],5) + sync_blocks(self.nodes) + + # Mine blocks on each node and then mine 100 to age them such that they are spendable. + print ("Mine more blocks on each node...") + self.nodes[1].generate(5) + sync_blocks(self.nodes) + self.nodes[2].generate(5) + sync_blocks(self.nodes) + self.nodes[3].generate(5) + sync_blocks(self.nodes) + self.nodes[4].generate(5) + sync_blocks(self.nodes) + self.nodes[5].generate(5) + sync_blocks(self.nodes) + self.nodes[1].generate(100) + sync_blocks(self.nodes) + + #stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=0"])) + + print ("Send more transactions...") + num_range = 50 + for i in range(num_range): + self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.01) + num_range = 10 + for i in range(num_range): + self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(), 0.01) + for i in range(num_range): + self.nodes[3].sendtoaddress(self.nodes[3].getnewaddress(), 0.01) + for i in range(num_range): + self.nodes[4].sendtoaddress(self.nodes[4].getnewaddress(), 0.01) + for i in range(num_range): + self.nodes[5].sendtoaddress(self.nodes[5].getnewaddress(), 0.01) + + # Mine 5 competing blocks. + print ("Mine 5 competing blocks...") + self.nodes[0].generate(1) + self.nodes[2].generate(1) + self.nodes[3].generate(1) + self.nodes[4].generate(1) + self.nodes[5].generate(1) + counts = [ x.getblockcount() for x in self.nodes ] + assert_equal(counts, [331,330,331,331,331,331]) + + # Connect nodes so that all blocks are sent at same time to node1. Largest block from node0 will be terminated. + print ("connnect nodes...") + connect_nodes(self.nodes[1],0) + connect_nodes(self.nodes[1],2) + connect_nodes(self.nodes[1],3) + connect_nodes(self.nodes[1],4) + connect_nodes(self.nodes[1],5) + sync_blocks(self.nodes) + + + # Mine a block which will cause a reorg back to node0 + print ("Mine another block...") + self.nodes[0].generate(1) + sync_blocks(self.nodes) + + # Mine 5 more competing blocks of the same size. The last block to arrive will have its validation terminated. + print ("Mine 5 more competing blocks...") + self.nodes[0].generate(1) + self.nodes[2].generate(1) + self.nodes[3].generate(1) + self.nodes[4].generate(1) + self.nodes[5].generate(1) + sync_blocks(self.nodes) + + # Mine another block which will cause the nodes to sync to one chain + print ("Mine another block...") + self.nodes[0].generate(1) + sync_blocks(self.nodes) + + #stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + # Cleanup by mining more blocks if we need to run extended tests + if self.longTest == True: + self.cleanup_and_reset() + + ################################################ + # Begin extended tests + ################################################ + if self.longTest == False: + return + + ########################################################################################### + # Test reorgs + ########################################################################################### + + ########################################################################################### + # Basic reorg - see section below on 4 block attack scenarios. At the end there is a + # repeated test that does basic reorgs multiple times. + + + ########################################################################################### + # 1) Start a slow to validate block race then mine another block pulling one chain ahead. + # - threads on the chain that is now not the most proof of work should be stopped and the + # most proof of work block should proceed. + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + + print ("Send more transactions...") + num_range = 15 + for i in range(num_range): + self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.01) + for i in range(num_range): + self.nodes[1].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) + for i in range(num_range): + self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(), 0.01) + + # Mine a block on each node + print ("Mine a block on each node..") + self.nodes[0].generate(1) + self.nodes[1].generate(1) + self.nodes[2].generate(1) + basecount = self.nodes[0].getblockcount() + + # Mine another block on node2 so that it's chain will be the longest when we connect it + print ("Mine another block on node2..") + self.nodes[2].generate(1) + bestblock = self.nodes[2].getbestblockhash() + + stop_nodes(self.nodes) + wait_bitcoinds() + + # Restart nodes with pvtest=1 + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=1"])) + + # Connect node 0 and 1 so that a block validation race begins + print ("Connect nodes0 and 1...") + connect_nodes(self.nodes[1],0) + + # Wait for a little while before connecting node 2 + time.sleep(3) + print ("Connect node2...") + counts = [ x.getblockcount() for x in self.nodes ] + print (str(counts)) + assert_equal(counts, [basecount,basecount,basecount+1]) + interconnect_nodes(self.nodes) + + # All chains will sync to node2 + sync_blocks(self.nodes) + assert_equal(self.nodes[0].getbestblockhash(), bestblock) + assert_equal(self.nodes[1].getbestblockhash(), bestblock) + assert_equal(self.nodes[2].getbestblockhash(), bestblock) + + stop_nodes(self.nodes) + wait_bitcoinds() + + # cleanup and sync chains for next tests + self.cleanup_and_reset() + + + ########################################################################################### + # Mine two forks of equal work and start slow to validate block race on fork1. Then another + # block arrives on fork2 + # - the slow to validate blocks will still continue + # Mine another block on fork2 two pulling that fork ahead. + # - threads on the fork1 should be stopped allowing fork2 to connect blocks and pull ahead + + print ("Mine two forks.") + # fork 1 (both nodes on fork1 should be syncd) + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + interconnect_nodes(self.nodes) + self.nodes[0].generate(1) + sync_blocks(self.nodes) + + # fork 2 + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes[2].generate(1) + + stop_nodes(self.nodes) + wait_bitcoinds() + + # restart nodes but don't connect them yet + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + + # Create txns on node0 and 1 to setup for a slow to validate race between those nodes. + print ("Send more transactions...") + num_range = 15 + for i in range(num_range): + self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.01) + for i in range(num_range): + self.nodes[1].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) + + # Mine a block on each node + print ("Mine a block on each node..") + self.nodes[0].generate(1) + self.nodes[1].generate(1) + self.nodes[2].generate(1) + basecount = self.nodes[0].getblockcount() + + # Mine another block on node2 so that it's chain will be the longest when we connect it + print ("Mine another block on node2..") + self.nodes[2].generate(1) + bestblock = self.nodes[2].getbestblockhash() + + stop_nodes(self.nodes) + wait_bitcoinds() + + # Restart nodes with pvtest=1 + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=1", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=1", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=1", "-whitelist=127.0.0.1"])) + + # Connect node 0 and 1 so that a block validation race begins + print ("Connect nodes0 and 1...") + connect_nodes(self.nodes[1],0) + + # Wait for a little while before connecting node 2 + time.sleep(3) + print ("Connect node2...") + counts = [ x.getblockcount() for x in self.nodes ] + print (str(counts)) + assert_equal(counts, [basecount,basecount,basecount+1]) + interconnect_nodes(self.nodes) + + # All chains will sync to node2 + sync_blocks(self.nodes) + assert_equal(self.nodes[0].getbestblockhash(), bestblock) + assert_equal(self.nodes[1].getbestblockhash(), bestblock) + assert_equal(self.nodes[2].getbestblockhash(), bestblock) + + stop_nodes(self.nodes) + wait_bitcoinds() + + # cleanup and sync chains for next tests + self.cleanup_and_reset() + + + ############################################################################################## + # Mine two forks of equal work and start slow to validate 4 block race on fork1. Then another + # block arrives on fork2 + # - the slow to validate blocks will still continue + # Mine another block on fork2 two pulling that fork ahead. + # - threads on the fork1 should be stopped allowing fork2 to connect blocks and pull ahead + + print ("Mine two forks.") + # fork 1 (both nodes on fork1 should be syncd) + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + interconnect_nodes(self.nodes) + self.nodes[0].generate(1) + sync_blocks(self.nodes) + + # fork 2 + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes[4].generate(1) + + stop_nodes(self.nodes) + wait_bitcoinds() + + # restart nodes but don't connect them yet + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + + # Create txns on node0 and 1 to setup for a slow to validate race between those nodes. + print ("Send more transactions...") + num_range = 15 + for i in range(num_range): + self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.01) + for i in range(num_range): + self.nodes[1].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) + for i in range(num_range): + self.nodes[3].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) + for i in range(num_range): + self.nodes[4].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) + + # Mine a block on each node + print ("Mine a block on each node..") + self.nodes[0].generate(1) + self.nodes[1].generate(1) + self.nodes[2].generate(1) + self.nodes[3].generate(1) + self.nodes[4].generate(1) + basecount = self.nodes[0].getblockcount() + + # Mine another block on node4 so that it's chain will be the longest when we connect it + print ("Mine another block on node4..") + self.nodes[4].generate(1) + bestblock = self.nodes[4].getbestblockhash() + + stop_nodes(self.nodes) + wait_bitcoinds() + + # Restart nodes with pvtest=1 + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=1", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=1", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=1", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=1", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=1", "-whitelist=127.0.0.1"])) + + # Connect node 0 and 1 so that a block validation race begins + print ("Connect nodes0, 1, 2 and 3...") + connect_nodes(self.nodes[1],0) + + # Wait for a little while before connecting node 4 + time.sleep(3) + print ("Connect node4...") + counts = [ x.getblockcount() for x in self.nodes ] + print (str(counts)) + assert_equal(counts, [basecount,basecount,basecount, basecount, basecount+1]) + interconnect_nodes(self.nodes) + + # All chains will sync to node2 + sync_blocks(self.nodes) + assert_equal(self.nodes[0].getbestblockhash(), bestblock) + assert_equal(self.nodes[1].getbestblockhash(), bestblock) + assert_equal(self.nodes[2].getbestblockhash(), bestblock) + assert_equal(self.nodes[3].getbestblockhash(), bestblock) + assert_equal(self.nodes[4].getbestblockhash(), bestblock) + + stop_nodes(self.nodes) + wait_bitcoinds() + + # cleanup and sync chains for next tests + self.cleanup_and_reset() + + + ########################################################################################### + # 1) Mine two forks of equal work and start slow to validate block race on fork1. Then another + # block arrives on fork2 pulling that fork ahead. + # - threads on the fork1 should be stopped allowing fork2 to connect blocks and pull ahead + # 2) As fork2 is being validated, fork 1 pulls ahead + # - fork 2 is now stopped and fork 1 begins to validate + # 3) do step 2 repeatedely, going back and forth between forks + + print ("Mine three forks.") + # fork 1 (both nodes on fork1 should be syncd) + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + interconnect_nodes(self.nodes) + self.nodes[0].generate(1) + sync_blocks(self.nodes) + + # fork 2 + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes[2].generate(1) + + # fork 3 + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes[3].generate(1) + + stop_nodes(self.nodes) + wait_bitcoinds() + + # restart nodes but don't connect them yet + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0", "-whitelist=127.0.0.1"])) + + # Create txns on node0 and 1 to setup for a slow to validate race between those nodes. + print ("Send more transactions...") + num_range = 15 + for i in range(num_range): + self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.01) + for i in range(num_range): + self.nodes[1].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) + + # in this test we also generate txns on node 2 so that all nodes will validate slowly. + for i in range(num_range): + self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) + + # Mine a block on each node + print ("Mine a block on each node..") + self.nodes[0].generate(1) + self.nodes[1].generate(1) + self.nodes[2].generate(1) + self.nodes[3].generate(1) + basecount = self.nodes[0].getblockcount() + + # Mine another block on node2 so that it's chain will be the longest when we connect it + print ("Mine another block on node2..") + self.nodes[2].generate(1) + + # Mine two blocks on node3 so that it's chain will be the longest when we connect it + print ("Mine 2 blocks on node3..") + self.nodes[3].generate(1) + self.nodes[3].generate(1) + bestblock = self.nodes[3].getbestblockhash() + + stop_nodes(self.nodes) + wait_bitcoinds() + + # Restart nodes with pvtest=1 + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=1", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=1", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=1", "-whitelist=127.0.0.1"])) + + # Connect node 0 and 1 so that a block validation race begins + print ("Connect nodes 0 and 1...") + connect_nodes(self.nodes[1],0) + + # Wait for a little while before connecting node 2 (fork2) + time.sleep(3) + print ("Connect node2 - fork2...") + counts = [ x.getblockcount() for x in self.nodes ] + print (str(counts)) + assert_equal(counts, [basecount,basecount,basecount+1]) + interconnect_nodes(self.nodes) + + # Wait for a little while before connecting node 3 (fork3) + time.sleep(3) + print ("Connect node3 - fork3...") + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug=","-pvtest=1", "-whitelist=127.0.0.1"])) + counts = [ x.getblockcount() for x in self.nodes ] + interconnect_nodes(self.nodes) + print (str(counts)) + assert_equal(counts, [basecount-1,basecount-1,basecount+1, basecount+2]) + interconnect_nodes(self.nodes) + + sync_blocks(self.nodes) + assert_equal(self.nodes[0].getbestblockhash(), bestblock) + assert_equal(self.nodes[1].getbestblockhash(), bestblock) + assert_equal(self.nodes[2].getbestblockhash(), bestblock) + assert_equal(self.nodes[3].getbestblockhash(), bestblock) + + stop_nodes(self.nodes) + wait_bitcoinds() + + # cleanup and sync chains for next tests + self.cleanup_and_reset() + + + ########################################################################################### + # 1) Large reorg - can we do a 144 block reorg? + print ("Starting repeating many competing blocks test") + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug=","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug=","-pvtest=0"])) + + print ("Mine 144 blocks on each chain...") + self.nodes[0].generate(144) + self.nodes[1].generate(144) + + print ("Connect nodes for larg reorg...") + connect_nodes(self.nodes[1],0) + sync_blocks(self.nodes) + + print ("Mine another block on node5 causing large reorg...") + self.nodes[1].generate(1) + sync_blocks(self.nodes) + + # Mine another block which will cause some nodes to reorg and sync to the same chain. + print ("Mine another block on node0...") + self.nodes[0].generate(1) + sync_blocks(self.nodes) + + # stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + # cleanup and sync chains for next tests + self.cleanup_and_reset() + + ########################################################################################### + # Test the 4 block attack scenarios - use -pvtest=true to slow down the checking of inputs. + ########################################################################################### + + #################################################################### + # Mine 4 blocks of all different sizes + # - the smallest block should win + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0"])) + + print ("Send more transactions...") + num_range = 15 + for i in range(num_range): + self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.01) + num_range = 14 + for i in range(num_range): + self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(), 0.01) + num_range = 13 + for i in range(num_range): + self.nodes[3].sendtoaddress(self.nodes[3].getnewaddress(), 0.01) + num_range = 2 + for i in range(num_range): + self.nodes[4].sendtoaddress(self.nodes[4].getnewaddress(), 0.01) + + # Mine 4 competing blocks. + print ("Mine 4 competing blocks...") + self.nodes[0].generate(1) + self.nodes[2].generate(1) + self.nodes[3].generate(1) + self.nodes[4].generate(1) + + # stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + # start nodes with -pvtest set to true. + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=1"])) + + # Connect nodes so that all blocks are sent at same time to node1. + connect_nodes(self.nodes[1],0) + connect_nodes(self.nodes[1],2) + connect_nodes(self.nodes[1],3) + connect_nodes(self.nodes[1],4) + sync_blocks(self.nodes) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[4].getbestblockhash()) + + # stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=0"])) + + connect_nodes(self.nodes[1],0) + connect_nodes(self.nodes[1],2) + connect_nodes(self.nodes[1],3) + connect_nodes(self.nodes[1],4) + connect_nodes(self.nodes[1],5) + sync_blocks(self.nodes) + + # Mine a block which will cause all nodes to update their chains + print ("Mine another block...") + self.nodes[1].generate(1) + time.sleep(2) #wait for blocks to propagate + sync_blocks(self.nodes) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[0].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[3].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[4].getbestblockhash()) + + #stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + # cleanup and sync chains for next tests + self.cleanup_and_reset() + + ######################################################################################################## + # Mine 4 blocks all the same size and get them to start validating and then send a 5th that is smaller + # - the last smallest and last block arriving should win. + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=0"])) + + print ("Send more transactions...") + num_range = 15 + for i in range(num_range): + self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.01) + num_range = 15 + for i in range(num_range): + self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(), 0.01) + num_range = 15 + for i in range(num_range): + self.nodes[3].sendtoaddress(self.nodes[3].getnewaddress(), 0.01) + num_range = 15 + for i in range(num_range): + self.nodes[4].sendtoaddress(self.nodes[4].getnewaddress(), 0.01) + num_range = 2 + for i in range(num_range): + self.nodes[5].sendtoaddress(self.nodes[5].getnewaddress(), 0.01) + + # stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + # start nodes with -pvtest set to true. + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=1"])) + + # Connect nodes so that first 4 blocks are sent at same time to node1. + connect_nodes(self.nodes[1],0) + connect_nodes(self.nodes[1],2) + connect_nodes(self.nodes[1],3) + connect_nodes(self.nodes[1],4) + time.sleep(5) #wait for blocks to start processing + + # Connect 5th block and this one should win the race + connect_nodes(self.nodes[1],5) + sync_blocks(self.nodes) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[5].getbestblockhash()) + + #stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=0"])) + + connect_nodes(self.nodes[1],0) + connect_nodes(self.nodes[1],2) + connect_nodes(self.nodes[1],3) + connect_nodes(self.nodes[1],4) + connect_nodes(self.nodes[1],5) + + # Mine a block which will cause all nodes to update their chains + print ("Mine another block...") + self.nodes[1].generate(1) + time.sleep(2) #wait for blocks to propagate + sync_blocks(self.nodes) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[0].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[3].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[4].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[5].getbestblockhash()) + + # stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + # cleanup and sync chains for next tests + self.cleanup_and_reset() + + ############################################################################################################ + # Mine 4 blocks all the same size and get them to start validating and then send a 5th that is the same size + # - the first block arriving should win + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=0"])) + + print ("Send more transactions...") + num_range = 10 + for i in range(num_range): + self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.01) + num_range = 10 + for i in range(num_range): + self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(), 0.01) + num_range = 10 + for i in range(num_range): + self.nodes[3].sendtoaddress(self.nodes[3].getnewaddress(), 0.01) + num_range = 10 + for i in range(num_range): + self.nodes[4].sendtoaddress(self.nodes[4].getnewaddress(), 0.01) + num_range = 10 + for i in range(num_range): + self.nodes[5].sendtoaddress(self.nodes[5].getnewaddress(), 0.01) + + # stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + # start nodes with -pvtest set to true. + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=1"])) + + # Connect nodes so that first 4 blocks are sent 1 second apart to node1. + connect_nodes(self.nodes[1],0) + time.sleep(1) + connect_nodes(self.nodes[1],2) + time.sleep(1) + connect_nodes(self.nodes[1],3) + time.sleep(1) + connect_nodes(self.nodes[1],4) + time.sleep(1) #wait for blocks to start processing + + # Connect 5th block and this one be terminated and the first block to connect from node0 should win the race + connect_nodes(self.nodes[1],5) + sync_blocks(self.nodes) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[0].getbestblockhash()) + + #stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=0"])) + + connect_nodes(self.nodes[1],0) + connect_nodes(self.nodes[1],2) + connect_nodes(self.nodes[1],3) + connect_nodes(self.nodes[1],4) + connect_nodes(self.nodes[1],5) + + # Mine a block which will cause all nodes to update their chains + print ("Mine another block...") + self.nodes[1].generate(1) + time.sleep(2) #wait for blocks to propagate + sync_blocks(self.nodes) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[0].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[3].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[4].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[5].getbestblockhash()) + + # stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + ######################################################################################################### + # Mine 4 blocks all the same size and get them to start validating and then send a 5th that is bigger + # - the first block arriving should win + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=0"])) + + print ("Send more transactions...") + num_range = 10 + for i in range(num_range): + self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.01) + num_range = 10 + for i in range(num_range): + self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(), 0.01) + num_range = 10 + for i in range(num_range): + self.nodes[3].sendtoaddress(self.nodes[3].getnewaddress(), 0.01) + num_range = 10 + for i in range(num_range): + self.nodes[4].sendtoaddress(self.nodes[4].getnewaddress(), 0.01) + num_range = 20 + for i in range(num_range): + self.nodes[5].sendtoaddress(self.nodes[5].getnewaddress(), 0.01) + + # stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + # start nodes with -pvtest set to true. + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=1"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=1"])) + + # Connect nodes so that first 4 blocks are sent 1 second apart to node1. + connect_nodes(self.nodes[1],0) + time.sleep(1) + connect_nodes(self.nodes[1],2) + time.sleep(1) + connect_nodes(self.nodes[1],3) + time.sleep(1) + connect_nodes(self.nodes[1],4) + time.sleep(1) #wait for blocks to start processing + + # Connect 5th block and this one be terminated and the first block to connect from node0 should win the race + connect_nodes(self.nodes[1],5) + sync_blocks(self.nodes) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[0].getbestblockhash()) + + # stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=0"])) + + connect_nodes(self.nodes[1],0) + connect_nodes(self.nodes[1],2) + connect_nodes(self.nodes[1],3) + connect_nodes(self.nodes[1],4) + connect_nodes(self.nodes[1],5) + + # Mine a block which will cause all nodes to update their chains + print ("Mine another block...") + self.nodes[1].generate(1) + time.sleep(2) #wait for blocks to propagate + sync_blocks(self.nodes) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[0].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[3].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[4].getbestblockhash()) + assert_equal(self.nodes[1].getbestblockhash(), self.nodes[5].getbestblockhash()) + + # stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + # cleanup and sync chains for next tests + self.cleanup_and_reset() + + + ################################################################################# + # Repeated 5 blocks mined with a reorg after + ################################################################################# + + # Repeatedly mine 5 blocks at a time on each node to have many blocks both arriving + # at the same time and racing each other to see which can extend the chain the fastest. + # This is intented just a stress test of the 4 block scenario but also while blocks + # are in the process of being both mined and with reorgs sometimes happening at the same time. + print ("Starting repeating many competing blocks test") + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(4, self.options.tmpdir, ["-debug","-pvtest=0"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-debug","-pvtest=0"])) + + connect_nodes(self.nodes[1],0) + connect_nodes(self.nodes[1],2) + connect_nodes(self.nodes[1],3) + connect_nodes(self.nodes[1],4) + connect_nodes(self.nodes[1],5) + sync_blocks(self.nodes) + + for i in range(100): + + print ("Mine many more competing blocks...") + self.nodes[0].generate(1) + self.nodes[2].generate(1) + self.nodes[3].generate(1) + self.nodes[4].generate(1) + self.nodes[5].generate(1) + sync_blocks(self.nodes) + + # Mine another block which will cause some nodes to reorg and sync to the same chain. + print ("Mine another block...") + self.nodes[0].generate(1) + sync_blocks(self.nodes) + + # stop nodes + stop_nodes(self.nodes) + wait_bitcoinds() + + # cleanup and sync chains for next tests + self.cleanup_and_reset() + +def Test(): + t = ParallelTest() + t.rep = True + t.main(["--tmpdir=/ramdisk/test", "--nocleanup","--noshutdown"]) + +if __name__ == '__main__': + + p = ParallelTest() + if "--rep" in sys.argv: + print("Repetitive test") + p.rep = True + sys.argv.remove("--rep") + else: + p.rep = False + + if "--extensive" in sys.argv: + p.longTest = True + # we must remove duplicate 'extensive' arg here + while True: + try: + sys.argv.remove('--extensive') + except: + break + print ("Running extensive tests") + else: + p.longTest = False + + + p.main () + diff --git a/qa/rpc-tests/prioritise_transaction.py b/qa/rpc-tests/prioritise_transaction.py new file mode 100644 index 00000000..589a958c --- /dev/null +++ b/qa/rpc-tests/prioritise_transaction.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test PrioritiseTransaction code +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.mininode import COIN, MAX_BLOCK_SIZE + +class PrioritiseTransactionTest(BitcoinTestFramework): + + def __init__(self): + self.txouts = gen_return_txouts() + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self): + self.nodes = [] + self.is_network_split = False + + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-printpriority=1"])) + self.relayfee = self.nodes[0].getnetworkinfo()['relayfee'] + + def run_test(self): + 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 range(3): + txids.append([]) + 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 range(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 + # the priority to ensure its not mined due to priority) + self.nodes[0].prioritisetransaction(txids[0][0], 0, int(3*base_fee*COIN)) + self.nodes[0].prioritisetransaction(txids[0][1], -1e15, 0) + + self.nodes[0].generate(1) + + mempool = self.nodes[0].getrawmempool() + print("Assert that prioritised transaction was mined") + assert(txids[0][0] not in mempool) + assert(txids[0][1] in mempool) + + high_fee_tx = None + for x in txids[2]: + if x not in mempool: + high_fee_tx = x + + # Something high-fee should have been mined! + assert(high_fee_tx != None) + + # Add a prioritisation before a tx is in the mempool (de-prioritising a + # 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 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + # Check to make sure our high fee rate tx is back in the mempool + mempool = self.nodes[0].getrawmempool() + assert(high_fee_tx in mempool) + + # 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. + mempool = self.nodes[0].getrawmempool() + print("Assert that de-prioritised transaction is still in mempool") + assert(high_fee_tx in mempool) + for x in txids[2]: + if (x != high_fee_tx): + assert(x not in mempool) + + # Create a free, low priority transaction. Should be rejected. + utxo_list = self.nodes[0].listunspent() + assert(len(utxo_list) > 0) + utxo = utxo_list[0] + + inputs = [] + outputs = {} + inputs.append({"txid" : utxo["txid"], "vout" : utxo["vout"]}) + outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee + raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) + tx_hex = self.nodes[0].signrawtransaction(raw_tx)["hex"] + txid = self.nodes[0].sendrawtransaction(tx_hex) + + # A tx that spends an in-mempool tx has 0 priority, so we can use it to + # test the effect of using prioritise transaction for mempool acceptance + inputs = [] + inputs.append({"txid": txid, "vout": 0}) + outputs = {} + outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee + raw_tx2 = self.nodes[0].createrawtransaction(inputs, outputs) + tx2_hex = self.nodes[0].signrawtransaction(raw_tx2)["hex"] + tx2_id = self.nodes[0].decoderawtransaction(tx2_hex)["txid"] + + try: + self.nodes[0].sendrawtransaction(tx2_hex) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) # insufficient fee + assert(tx2_id not in self.nodes[0].getrawmempool()) + else: + assert(False) + + # This is a less than 1000-byte transaction, so just set the fee + # to be the minimum for a 1000 byte transaction and check that it is + # accepted. + self.nodes[0].prioritisetransaction(tx2_id, 0, int(self.relayfee*COIN)) + + print("Assert that prioritised free transaction is accepted to mempool") + assert_equal(self.nodes[0].sendrawtransaction(tx2_hex), tx2_id) + assert(tx2_id in self.nodes[0].getrawmempool()) + +if __name__ == '__main__': + PrioritiseTransactionTest().main() diff --git a/qa/rpc-tests/proxy_test.py b/qa/rpc-tests/proxy_test.py new file mode 100644 index 00000000..c87d6915 --- /dev/null +++ b/qa/rpc-tests/proxy_test.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import socket + +from test_framework.socks5 import Socks5Configuration, Socks5Command, Socks5Server, AddressType +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.netutil import test_ipv6_local +''' +Test plan: +- Start bitcoind's with different proxy configurations +- Use addnode to initiate connections +- Verify that proxies are connected to, and the right connection command is given +- Proxy configurations to test on bitcoind side: + - `-proxy` (proxy everything) + - `-onion` (proxy just onions) + - `-proxyrandomize` Circuit randomization +- Proxy configurations to test on proxy side, + - support no authentication (other proxy) + - support no authentication + user/pass authentication (Tor) + - proxy on IPv6 + +- Create various proxies (as threads) +- Create bitcoinds that connect to them +- Manipulate the bitcoinds using addnode (onetry) an observe effects + +addnode connect to IPv4 +addnode connect to IPv6 +addnode connect to onion +addnode connect to generic DNS name +''' + + +class ProxyTest(BitcoinTestFramework): + def __init__(self): + self.have_ipv6 = test_ipv6_local() + # Create two proxies on different ports + # ... one unauthenticated + self.conf1 = Socks5Configuration() + self.conf1.addr = ('127.0.0.1', 13000 + (os.getpid() % 1000)) + self.conf1.unauth = True + self.conf1.auth = False + # ... one supporting authenticated and unauthenticated (Tor) + self.conf2 = Socks5Configuration() + self.conf2.addr = ('127.0.0.1', 14000 + (os.getpid() % 1000)) + self.conf2.unauth = True + self.conf2.auth = True + if self.have_ipv6: + # ... one on IPv6 with similar configuration + self.conf3 = Socks5Configuration() + self.conf3.af = socket.AF_INET6 + self.conf3.addr = ('::1', 15000 + (os.getpid() % 1000)) + self.conf3.unauth = True + self.conf3.auth = True + else: + print("Warning: testing without local IPv6 support") + + self.serv1 = Socks5Server(self.conf1) + self.serv1.start() + self.serv2 = Socks5Server(self.conf2) + self.serv2.start() + if self.have_ipv6: + self.serv3 = Socks5Server(self.conf3) + self.serv3.start() + + def setup_nodes(self): + # Note: proxies are not used to connect to local nodes + # this is because the proxy to use is based on CService.GetNetwork(), which return NET_UNROUTABLE for localhost + args = [ + ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'], + ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'], + ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'], + [] + ] + if self.have_ipv6: + args[3] = ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion'] + return start_nodes(4, self.options.tmpdir, extra_args=args) + + def node_test(self, node, proxies, auth, test_onion=True): + rv = [] + # Test: outgoing IPv4 connection through node + node.addnode("15.61.23.23:1234", "onetry") + cmd = proxies[0].queue.get() + assert(isinstance(cmd, Socks5Command)) + # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 + assert_equal(cmd.atyp, AddressType.DOMAINNAME) + assert_equal(cmd.addr, b"15.61.23.23") + assert_equal(cmd.port, 1234) + if not auth: + assert_equal(cmd.username, None) + assert_equal(cmd.password, None) + rv.append(cmd) + + if self.have_ipv6: + # Test: outgoing IPv6 connection through node + node.addnode("[1233:3432:2434:2343:3234:2345:6546:4534]:5443", "onetry") + cmd = proxies[1].queue.get() + assert(isinstance(cmd, Socks5Command)) + # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 + assert_equal(cmd.atyp, AddressType.DOMAINNAME) + assert_equal(cmd.addr, b"1233:3432:2434:2343:3234:2345:6546:4534") + assert_equal(cmd.port, 5443) + if not auth: + assert_equal(cmd.username, None) + assert_equal(cmd.password, None) + rv.append(cmd) + + if test_onion: + # Test: outgoing onion connection through node + node.addnode("bitcoinostk4e4re.onion:8333", "onetry") + cmd = proxies[2].queue.get() + assert(isinstance(cmd, Socks5Command)) + assert_equal(cmd.atyp, AddressType.DOMAINNAME) + assert_equal(cmd.addr, b"bitcoinostk4e4re.onion") + assert_equal(cmd.port, 8333) + if not auth: + assert_equal(cmd.username, None) + assert_equal(cmd.password, None) + rv.append(cmd) + + # Test: outgoing DNS name connection through node + node.addnode("node.noumenon:8333", "onetry") + cmd = proxies[3].queue.get() + assert(isinstance(cmd, Socks5Command)) + assert_equal(cmd.atyp, AddressType.DOMAINNAME) + assert_equal(cmd.addr, b"node.noumenon") + assert_equal(cmd.port, 8333) + if not auth: + assert_equal(cmd.username, None) + assert_equal(cmd.password, None) + rv.append(cmd) + + return rv + + def run_test(self): + # basic -proxy + self.node_test(self.nodes[0], [self.serv1, self.serv1, self.serv1, self.serv1], False) + + # -proxy plus -onion + self.node_test(self.nodes[1], [self.serv1, self.serv1, self.serv2, self.serv1], False) + + # -proxy plus -onion, -proxyrandomize + rv = self.node_test(self.nodes[2], [self.serv2, self.serv2, self.serv2, self.serv2], True) + # Check that credentials as used for -proxyrandomize connections are unique + credentials = set((x.username,x.password) for x in rv) + assert_equal(len(credentials), len(rv)) + + if self.have_ipv6: + # proxy on IPv6 localhost + self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3], False, False) + + def networks_dict(d): + r = {} + for x in d['networks']: + r[x['name']] = x + return r + + # test RPC getnetworkinfo + n0 = networks_dict(self.nodes[0].getnetworkinfo()) + for net in ['ipv4','ipv6','onion']: + assert_equal(n0[net]['proxy'], '%s:%i' % (self.conf1.addr)) + assert_equal(n0[net]['proxy_randomize_credentials'], True) + assert_equal(n0['onion']['reachable'], True) + + n1 = networks_dict(self.nodes[1].getnetworkinfo()) + for net in ['ipv4','ipv6']: + assert_equal(n1[net]['proxy'], '%s:%i' % (self.conf1.addr)) + assert_equal(n1[net]['proxy_randomize_credentials'], False) + assert_equal(n1['onion']['proxy'], '%s:%i' % (self.conf2.addr)) + assert_equal(n1['onion']['proxy_randomize_credentials'], False) + assert_equal(n1['onion']['reachable'], True) + + n2 = networks_dict(self.nodes[2].getnetworkinfo()) + for net in ['ipv4','ipv6','onion']: + assert_equal(n2[net]['proxy'], '%s:%i' % (self.conf2.addr)) + assert_equal(n2[net]['proxy_randomize_credentials'], True) + assert_equal(n2['onion']['reachable'], True) + + if self.have_ipv6: + n3 = networks_dict(self.nodes[3].getnetworkinfo()) + for net in ['ipv4','ipv6']: + assert_equal(n3[net]['proxy'], '[%s]:%i' % (self.conf3.addr)) + assert_equal(n3[net]['proxy_randomize_credentials'], False) + assert_equal(n3['onion']['reachable'], False) + +if __name__ == '__main__': + ProxyTest().main() + diff --git a/qa/rpc-tests/pruning.py b/qa/rpc-tests/pruning.py new file mode 100644 index 00000000..de1eb0ab --- /dev/null +++ b/qa/rpc-tests/pruning.py @@ -0,0 +1,388 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test pruning code +# ******** +# WARNING: +# This test uses 4GB of disk space. +# This test takes 30 mins or more (up to 2 hours) +# ******** + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +def calc_usage(blockdir): + return sum(os.path.getsize(blockdir+f) for f in os.listdir(blockdir) if os.path.isfile(blockdir+f)) / (1024. * 1024.) + +class PruneTest(BitcoinTestFramework): + + def __init__(self): + self.utxo = [] + self.address = ["",""] + self.txouts = gen_return_txouts() + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self): + self.nodes = [] + self.is_network_split = False + + # Create nodes 0 and 1 to mine + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-rpcservertimeout=0", "-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900)) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-rpcservertimeout=0", "-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900)) + + # Create node 2 to test pruning + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-rpcservertimeout=0", "-maxreceivebuffer=20000","-prune=550"], timewait=900)) + self.prunedir = self.options.tmpdir+"/node2/regtest/blocks/" + + self.address[0] = self.nodes[0].getnewaddress() + self.address[1] = self.nodes[1].getnewaddress() + + # Determine default relay fee + self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"] + + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[1], 2) + connect_nodes(self.nodes[2], 0) + sync_blocks(self.nodes[0:3]) + + def create_big_chain(self): + # Start by creating some coinbases we can spend later + self.nodes[1].generate(200) + sync_blocks(self.nodes[0:2]) + self.nodes[0].generate(150) + # Then mine enough full blocks to create more than 550MiB of data + for i in range(645): + self.mine_full_block(self.nodes[0], self.address[0]) + sync_blocks(self.nodes[0:3]) + + def test_height_min(self): + if not os.path.isfile(self.prunedir+"blk00000.dat"): + raise AssertionError("blk00000.dat is missing, pruning too early") + print("Success") + print("Though we're already using more than 550MiB, current usage:", calc_usage(self.prunedir)) + print("Mining 25 more blocks should cause the first block file to be pruned") + # Pruning doesn't run until we're allocating another chunk, 20 full blocks past the height cutoff will ensure this + for i in range(25): + counts = [ x.getblockcount() for x in self.nodes ] + print(counts) + self.mine_full_block(self.nodes[0],self.address[0]) + + waitstart = time.time() + while os.path.isfile(self.prunedir+"blk00000.dat"): + time.sleep(0.1) + if time.time() - waitstart > 10: + raise AssertionError("blk00000.dat not pruned when it should be") + + print("Success") + usage = calc_usage(self.prunedir) + print("Usage should be below target:", usage) + if (usage > 550): + raise AssertionError("Pruning target not being met") + + def test_height_after_sync(self): + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug","-rpcservertimeout=0", "-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900)) + self.prunedir = self.options.tmpdir+"/node3/regtest/blocks/" + connect_nodes(self.nodes[3], 1) + # wait for the first blocks to arrive on node3 before mining the next + # blocks. We have to make sure the first block file has a starting height + # before doing any mining. + while self.nodes[3].getblockcount() <= 0: + time.sleep(0.1) + + # Mine several new blocks while the chain on node 3 is syncing. This + # should not allow new blocks to get into the block files until we + # are within 144 blocks of the chain tip. If new blocks do get into the + # first block file then we won't be able to prune it and the test will fail. + for i in range(20): + print ("generate a block") + self.nodes[1].generate(1) + counts = [ x.getblockcount() for x in self.nodes ] + print(counts) + time.sleep(0.5) + sync_blocks(self.nodes) + + #check that first block file was pruned. + waitstart = time.time() + while os.path.isfile(self.prunedir+"blk00000.dat"): + time.sleep(0.1) + if time.time() - waitstart > 10: + raise AssertionError("blk00000.dat not pruned when it should be") + + print("Success") + usage = calc_usage(self.prunedir) + print("Usage should be below target:", usage) + if (usage > 550): + raise AssertionError("Pruning target not being met") + + + def create_chain_with_staleblocks(self): + # Create stale blocks in manageable sized chunks + print("Mine 24 (stale) blocks on Node 1, followed by 25 (main chain) block reorg from Node 0, for 12 rounds") + + for j in range(12): + # Disconnect node 0 so it can mine a longer reorg chain without knowing about node 1's soon-to-be-stale chain + # Node 2 stays connected, so it hears about the stale blocks and then reorg's when node0 reconnects + # Stopping node 0 also clears its mempool, so it doesn't have node1's transactions to accidentally mine + stop_node(self.nodes[0],0) + self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-rpcservertimeout=0", "-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900) + # Mine 24 blocks in node 1 + self.utxo = self.nodes[1].listunspent() + for i in range(24): + if j == 0: + self.mine_full_block(self.nodes[1],self.address[1]) + else: + self.nodes[1].generate(1) #tx's already in mempool from previous disconnects + + # Reorg back with 25 block chain from node 0 + self.utxo = self.nodes[0].listunspent() + for i in range(25): + self.mine_full_block(self.nodes[0],self.address[0]) + + # Create connections in the order so both nodes can see the reorg at the same time + connect_nodes(self.nodes[1], 0) + connect_nodes(self.nodes[2], 0) + sync_blocks(self.nodes[0:3]) + + print("Usage can be over target because of high stale rate:", calc_usage(self.prunedir)) + + def reorg_test(self): + # Node 1 will mine a 300 block chain starting 287 blocks back from Node 0 and Node 2's tip + # This will cause Node 2 to do a reorg requiring 288 blocks of undo data to the reorg_test chain + # Reboot node 1 to clear its mempool (hopefully make the invalidate faster) + # Lower the block max size so we don't keep mining all our big mempool transactions (from disconnected blocks) + stop_node(self.nodes[1],1) + self.nodes[1]=start_node(1, self.options.tmpdir, ["-debug","-rpcservertimeout=0", "-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900) + + height = self.nodes[1].getblockcount() + print("Current block height:", height) + + invalidheight = height-287 + badhash = self.nodes[1].getblockhash(invalidheight) + print("Invalidating block at height:",invalidheight,badhash) + self.nodes[1].invalidateblock(badhash) + + # We've now switched to our previously mined-24 block fork on node 1, but thats not what we want + # So invalidate that fork as well, until we're on the same chain as node 0/2 (but at an ancestor 288 blocks ago) + mainchainhash = self.nodes[0].getblockhash(invalidheight - 1) + curhash = self.nodes[1].getblockhash(invalidheight - 1) + while curhash != mainchainhash: + self.nodes[1].invalidateblock(curhash) + curhash = self.nodes[1].getblockhash(invalidheight - 1) + + assert(self.nodes[1].getblockcount() == invalidheight - 1) + print("New best height", self.nodes[1].getblockcount()) + + # Reboot node1 to clear those giant tx's from mempool + stop_node(self.nodes[1],1) + self.nodes[1]=start_node(1, self.options.tmpdir, ["-debug","-rpcservertimeout=0", "-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900) + + print("Generating new longer chain of 300 more blocks") + self.nodes[1].generate(300) + + print("Reconnect nodes") + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[2], 1) + sync_blocks(self.nodes[0:3]) + + print("Verify height on node 2:",self.nodes[2].getblockcount()) + print("Usage possibly still high bc of stale blocks in block files:", calc_usage(self.prunedir)) + + #top_node(self.nodes[1],1) + print("Mine 220 more blocks so we have requisite history (some blocks will be big and cause pruning of previous chain)") + for i in range(220): + self.nodes[0].generate(1) + sync_blocks(self.nodes[0:3]) + + usage = calc_usage(self.prunedir) + print("Usage should be below target:", usage) + if (usage > 550): + raise AssertionError("Pruning target not being met") + + return invalidheight,badhash + + def reorg_back(self): + # Verify that a block on the old main chain fork has been pruned away + try: + self.nodes[2].getblock(self.forkhash) + raise AssertionError("Old block wasn't pruned so can't test redownload") + except JSONRPCException as e: + print("Will need to redownload block",self.forkheight) + + # Verify that we have enough history to reorg back to the fork point + # Although this is more than 288 blocks, because this chain was written more recently + # and only its other 299 small and 220 large block are in the block files after it, + # its expected to still be retained + self.nodes[2].getblock(self.nodes[2].getblockhash(self.forkheight)) + + first_reorg_height = self.nodes[2].getblockcount() + curchainhash = self.nodes[2].getblockhash(self.mainchainheight) + self.nodes[2].invalidateblock(curchainhash) + goalbestheight = self.mainchainheight + goalbesthash = self.mainchainhash2 + + # As of 0.10 the current block download logic is not able to reorg to the original chain created in + # create_chain_with_stale_blocks because it doesn't know of any peer thats on that chain from which to + # redownload its missing blocks. + # Invalidate the reorg_test chain in node 0 as well, it can successfully switch to the original chain + # because it has all the block data. + # However it must mine enough blocks to have a more work chain than the reorg_test chain in order + # to trigger node 2's block download logic. + # At this point node 2 is within 288 blocks of the fork point so it will preserve its ability to reorg + if self.nodes[2].getblockcount() < self.mainchainheight: + blocks_to_mine = first_reorg_height + 1 - self.mainchainheight + print("Rewind node 0 to prev main chain to mine longer chain to trigger redownload. Blocks needed:", blocks_to_mine) + self.nodes[0].invalidateblock(curchainhash) + assert(self.nodes[0].getblockcount() == self.mainchainheight) + assert(self.nodes[0].getbestblockhash() == self.mainchainhash2) + goalbesthash = self.nodes[0].generate(blocks_to_mine)[-1] + goalbestheight = first_reorg_height + 1 + + print("Verify node 2 reorged back to the main chain, some blocks of which it had to redownload") + waitstart = time.time() + while self.nodes[2].getblockcount() < goalbestheight: + time.sleep(0.1) + if time.time() - waitstart > 900: + raise AssertionError("Node 2 didn't reorg to proper height") + assert(self.nodes[2].getbestblockhash() == goalbesthash) + # Verify we can now have the data for a block previously pruned + assert(self.nodes[2].getblock(self.forkhash)["height"] == self.forkheight) + + def mine_full_block(self, node, address): + # Want to create a full block + # We'll generate a 66k transaction below, and 14 of them is close to the 1MB block limit + for j in range(14): + if len(self.utxo) < 14: + self.utxo = node.listunspent() + inputs=[] + outputs = {} + t = self.utxo.pop() + inputs.append({ "txid" : t["txid"], "vout" : t["vout"]}) + remchange = t["amount"] - 100*self.relayfee # Fee must be above min relay rate for 66kb tx + outputs[address]=remchange + # Create a basic transaction that will send change back to ourself after account for a fee + # And then insert the 128 generated transaction outs in the middle rawtx[92] is where the # + # of txouts is stored and is the only thing we overwrite from the original transaction + rawtx = node.createrawtransaction(inputs, outputs) + newtx = rawtx[0:92] + newtx = newtx + self.txouts + newtx = newtx + rawtx[94:] + # Appears to be ever so slightly faster to sign with SIGHASH_NONE + signresult = node.signrawtransaction(newtx,None,None,"NONE") + txid = node.sendrawtransaction(signresult["hex"], True) + # Mine a full sized block which will be these transactions we just created + node.generate(1) + + + def run_test(self): + print("Warning! This test requires 4GB of disk space and takes over 30 mins (up to 2 hours)") + print("Mining a big blockchain of 995 blocks") + self.create_big_chain() + # Chain diagram key: + # * blocks on main chain + # +,&,$,@ blocks on other forks + # X invalidated block + # N1 Node 1 + # + # Start by mining a simple chain that all nodes have + # N0=N1=N2 **...*(995) + + print("Check that we haven't started pruning yet because we're below PruneAfterHeight") + self.test_height_min() + # Extend this chain past the PruneAfterHeight + # N0=N1=N2 **...*(1020) + + print("Check that block files are pruned after a sync that has also mined new blocks") + # When new blocks are mined while a node is syncing the chain from the beginning, + # thos newly mined blocks should not get included in a block file until the chain is almost + # sync'd. If this were to be allowed to happen then those early block files may not be + # prunable because they contain newer blocks. + #self.test_height_after_sync() TODO: comment out for now until we can fix the "regtest" issue with IBD and new blocks + + print("Check that we'll exceed disk space target if we have a very high stale block rate") + self.create_chain_with_staleblocks() + # Disconnect N0 + # And mine a 24 block chain on N1 and a separate 25 block chain on N0 + # N1=N2 **...*+...+(1044) + # N0 **...**...**(1045) + # + # reconnect nodes causing reorg on N1 and N2 + # N1=N2 **...*(1020) *...**(1045) + # \ + # +...+(1044) + # + # repeat this process until you have 12 stale forks hanging off the + # main chain on N1 and N2 + # N0 *************************...***************************(1320) + # + # N1=N2 **...*(1020) *...**(1045) *.. ..**(1295) *...**(1320) + # \ \ \ + # +...+(1044) &.. $...$(1319) + + # Save some current chain state for later use + self.mainchainheight = self.nodes[2].getblockcount() #1320 + self.mainchainhash2 = self.nodes[2].getblockhash(self.mainchainheight) + + print("Check that we can survive a 288 block reorg still") + (self.forkheight,self.forkhash) = self.reorg_test() #(1033, ) + # Now create a 288 block reorg by mining a longer chain on N1 + # First disconnect N1 + # Then invalidate 1033 on main chain and 1032 on fork so height is 1032 on main chain + # N1 **...*(1020) **...**(1032)X.. + # \ + # ++...+(1031)X.. + # + # Now mine 300 more blocks on N1 + # N1 **...*(1020) **...**(1032) @@...@(1332) + # \ \ + # \ X... + # \ \ + # ++...+(1031)X.. .. + # + # Reconnect nodes and mine 220 more blocks on N1 + # N1 **...*(1020) **...**(1032) @@...@@@(1552) + # \ \ + # \ X... + # \ \ + # ++...+(1031)X.. .. + # + # N2 **...*(1020) **...**(1032) @@...@@@(1552) + # \ \ + # \ *...**(1320) + # \ \ + # ++...++(1044) .. + # + # N0 ********************(1032) @@...@@@(1552) + # \ + # *...**(1320) + + print("Test that we can rerequest a block we previously pruned if needed for a reorg") + self.reorg_back() + # Verify that N2 still has block 1033 on current chain (@), but not on main chain (*) + # Invalidate 1033 on current chain (@) on N2 and we should be able to reorg to + # original main chain (*), but will require redownload of some blocks + # In order to have a peer we think we can download from, must also perform this invalidation + # on N0 and mine a new longest chain to trigger. + # Final result: + # N0 ********************(1032) **...****(1553) + # \ + # X@...@@@(1552) + # + # N2 **...*(1020) **...**(1032) **...****(1553) + # \ \ + # \ X@...@@@(1552) + # \ + # +.. + # + # N1 doesn't change because 1033 on main chain (*) is invalid + + print("Done") + +if __name__ == '__main__': + PruneTest().main() diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py new file mode 100644 index 00000000..dd031381 --- /dev/null +++ b/qa/rpc-tests/rawtransactions.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test re-org scenarios with a mempool that contains transactions +# that spend (directly or indirectly) coinbase transactions. +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +# Create one-input, one-output, no-fee transaction: +class RawTransactionsTest(BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 3) + + def setup_network(self, split=False): + self.nodes = start_nodes(3, self.options.tmpdir) + + #connect to a local machine for debugging + #url = "http://bitcoinrpc:DP6DvqZtqXarpeNWyN3LZTFchCCyCUuHwNF7E8pX99x1@%s:%d" % ('127.0.0.1', 18332) + #proxy = AuthServiceProxy(url) + #proxy.url = url # store URL on proxy for info + #self.nodes.append(proxy) + + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + + self.is_network_split=False + self.sync_all() + + def run_test(self): + + #prepare some coins for multiple *rawtransaction commands + self.nodes[2].generate(1) + self.sync_all() + self.nodes[0].generate(101) + self.sync_all() + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5) + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0) + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),5.0) + self.sync_all() + self.nodes[0].generate(5) + self.sync_all() + + ######################################### + # sendrawtransaction with missing input # + ######################################### + inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1}] #won't exists + outputs = { self.nodes[0].getnewaddress() : 4.998 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + rawtx = self.nodes[2].signrawtransaction(rawtx) + + try: + rawtx = self.nodes[2].sendrawtransaction(rawtx['hex']) + except JSONRPCException as e: + assert("Missing inputs" in e.error['message']) + else: + assert(False) + + + ######################### + # RAW TX MULTISIG TESTS # + ######################### + # 2of2 test + addr1 = self.nodes[2].getnewaddress() + addr2 = self.nodes[2].getnewaddress() + + addr1Obj = self.nodes[2].validateaddress(addr1) + addr2Obj = self.nodes[2].validateaddress(addr2) + + mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) + mSigObjValid = self.nodes[2].validateaddress(mSigObj) + + #use balance deltas instead of absolute values + bal = self.nodes[2].getbalance() + + # send 1.2 BTC to msig adr + txId = self.nodes[0].sendtoaddress(mSigObj, 1.2) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + assert_equal(self.nodes[2].getbalance(), bal+Decimal('1.20000000')) #node2 has both keys of the 2of2 ms addr., tx should affect the balance + + + # 2of3 test from different nodes + bal = self.nodes[2].getbalance() + addr1 = self.nodes[1].getnewaddress() + addr2 = self.nodes[2].getnewaddress() + addr3 = self.nodes[2].getnewaddress() + + addr1Obj = self.nodes[1].validateaddress(addr1) + addr2Obj = self.nodes[2].validateaddress(addr2) + addr3Obj = self.nodes[2].validateaddress(addr3) + + mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']]) + mSigObjValid = self.nodes[2].validateaddress(mSigObj) + + txId = self.nodes[0].sendtoaddress(mSigObj, 2.2) + decTx = self.nodes[0].gettransaction(txId) + rawTx = self.nodes[0].decoderawtransaction(decTx['hex']) + sPK = rawTx['vout'][0]['scriptPubKey']['hex'] + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + #THIS IS A INCOMPLETE FEATURE + #NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND COUNT AT BALANCE CALCULATION + assert_equal(self.nodes[2].getbalance(), bal) #for now, assume the funds of a 2of3 multisig tx are not marked as spendable + + txDetails = self.nodes[0].gettransaction(txId, True) + decrawTx = self.nodes[0].decoderawtransaction(txDetails['hex']) + vout = False + for outpoint in decrawTx['vout']: + if outpoint['value'] == Decimal('2.20000000'): + vout = outpoint + break + + bal = self.nodes[0].getbalance() + inputs = [{ "txid" : txId, "vout" : vout['n'], "scriptPubKey" : vout['scriptPubKey']['hex'], "amount":vout['value'] }] + outputs = { self.nodes[0].getnewaddress() : 2.19 } + rawTx = self.nodes[2].createrawtransaction(inputs, outputs) + rawTxPartialSigned = self.nodes[1].signrawtransaction(rawTx, inputs) + assert_equal(rawTxPartialSigned['complete'], False) #node1 only has one key, can't comp. sign the tx + rawTxSigned = self.nodes[2].signrawtransaction(rawTx, inputs) + assert_equal(rawTxSigned['complete'], True) #node2 can sign the tx compl., own two of three keys + self.nodes[2].sendrawtransaction(rawTxSigned['hex']) + rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex']) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx + +if __name__ == '__main__': + RawTransactionsTest().main() + +def Test(): + t = RawTransactionsTest() + t.drop_to_pdb = True + bitcoinConf = { + "debug": ["net", "blk", "thin", "mempool", "req", "bench", "evict"], # "lck" + "blockprioritysize": 2000000 # we don't want any transactions rejected due to insufficient fees... + } + t.main(["--tmpdir=/ramdisk/test","--nocleanup","--noshutdown"], bitcoinConf, None) # , "--tracerpc"]) diff --git a/qa/rpc-tests/receivedby.py b/qa/rpc-tests/receivedby.py new file mode 100644 index 00000000..ad5641ad --- /dev/null +++ b/qa/rpc-tests/receivedby.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# Exercise the listreceivedbyaddress API + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + + +def get_sub_array_from_array(object_array, to_match): + ''' + Finds and returns a sub array from an array of arrays. + to_match should be a unique idetifier of a sub array + ''' + num_matched = 0 + for item in object_array: + all_match = True + for key,value in to_match.items(): + if item[key] != value: + all_match = False + if not all_match: + continue + return item + return [] + +class ReceivedByTest(BitcoinTestFramework): + + def setup_nodes(self): + enable_mocktime() + return start_nodes(4, self.options.tmpdir) + + def run_test(self): + ''' + listreceivedbyaddress Test + ''' + # Send from node 0 to 1 + addr = self.nodes[1].getnewaddress() + txid = self.nodes[0].sendtoaddress(addr, 0.1) + self.sync_all() + + #Check not listed in listreceivedbyaddress because has 0 confirmations + assert_array_result(self.nodes[1].listreceivedbyaddress(), + {"address":addr}, + { }, + True) + #Bury Tx under 10 block so it will be returned by listreceivedbyaddress + self.nodes[1].generate(10) + self.sync_all() + assert_array_result(self.nodes[1].listreceivedbyaddress(), + {"address":addr}, + {"address":addr, "account":"", "amount":Decimal("0.1"), "confirmations":10, "txids":[txid,]}) + #With min confidence < 10 + assert_array_result(self.nodes[1].listreceivedbyaddress(5), + {"address":addr}, + {"address":addr, "account":"", "amount":Decimal("0.1"), "confirmations":10, "txids":[txid,]}) + #With min confidence > 10, should not find Tx + assert_array_result(self.nodes[1].listreceivedbyaddress(11),{"address":addr},{ },True) + + #Empty Tx + addr = self.nodes[1].getnewaddress() + assert_array_result(self.nodes[1].listreceivedbyaddress(0,True), + {"address":addr}, + {"address":addr, "account":"", "amount":0, "confirmations":0, "txids":[]}) + + ''' + getreceivedbyaddress Test + ''' + # Send from node 0 to 1 + addr = self.nodes[1].getnewaddress() + txid = self.nodes[0].sendtoaddress(addr, 0.1) + self.sync_all() + + #Check balance is 0 because of 0 confirmations + balance = self.nodes[1].getreceivedbyaddress(addr) + if balance != Decimal("0.0"): + raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance)) + + #Check balance is 0.1 + balance = self.nodes[1].getreceivedbyaddress(addr,0) + if balance != Decimal("0.1"): + raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance)) + + #Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress + self.nodes[1].generate(10) + self.sync_all() + balance = self.nodes[1].getreceivedbyaddress(addr) + if balance != Decimal("0.1"): + raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance)) + + ''' + listreceivedbyaccount + getreceivedbyaccount Test + ''' + #set pre-state + addrArr = self.nodes[1].getnewaddress() + account = self.nodes[1].getaccount(addrArr) + received_by_account_json = get_sub_array_from_array(self.nodes[1].listreceivedbyaccount(),{"account":account}) + if len(received_by_account_json) == 0: + raise AssertionError("No accounts found in node") + balance_by_account = rec_by_accountArr = self.nodes[1].getreceivedbyaccount(account) + + txid = self.nodes[0].sendtoaddress(addr, 0.1) + self.sync_all() + + # listreceivedbyaccount should return received_by_account_json because of 0 confirmations + assert_array_result(self.nodes[1].listreceivedbyaccount(), + {"account":account}, + received_by_account_json) + + # getreceivedbyaddress should return same balance because of 0 confirmations + balance = self.nodes[1].getreceivedbyaccount(account) + if balance != balance_by_account: + raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance)) + + self.nodes[1].generate(10) + self.sync_all() + # listreceivedbyaccount should return updated account balance + assert_array_result(self.nodes[1].listreceivedbyaccount(), + {"account":account}, + {"account":received_by_account_json["account"], "amount":(received_by_account_json["amount"] + Decimal("0.1"))}) + + # getreceivedbyaddress should return updates balance + balance = self.nodes[1].getreceivedbyaccount(account) + if balance != balance_by_account + Decimal("0.1"): + raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance)) + + #Create a new account named "mynewaccount" that has a 0 balance + self.nodes[1].getaccountaddress("mynewaccount") + received_by_account_json = get_sub_array_from_array(self.nodes[1].listreceivedbyaccount(0,True),{"account":"mynewaccount"}) + if len(received_by_account_json) == 0: + raise AssertionError("No accounts found in node") + + # Test includeempty of listreceivedbyaccount + if received_by_account_json["amount"] != Decimal("0.0"): + raise AssertionError("Wrong balance returned by listreceivedbyaccount, %0.2f"%(received_by_account_json["amount"])) + + # Test getreceivedbyaccount for 0 amount accounts + balance = self.nodes[1].getreceivedbyaccount("mynewaccount") + if balance != Decimal("0.0"): + raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance)) + +if __name__ == '__main__': + ReceivedByTest().main() diff --git a/qa/rpc-tests/reindex.py b/qa/rpc-tests/reindex.py new file mode 100644 index 00000000..06da1ecb --- /dev/null +++ b/qa/rpc-tests/reindex.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test -reindex with CheckBlockIndex +# +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class ReindexTest(BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 2) + + def setup_network(self): + self.nodes = [] + self.is_network_split = False + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-checkblockindex=1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-checkblockindex=1"])) + interconnect_nodes(self.nodes) + + def run_test(self): + + # Generate enough blocks that we can spend some coinbase. + nBlocks = 101 + self.nodes[0].generate(nBlocks) + self.sync_all() + + # Generate transactions and mine them so there is a UTXO that is created. + num_range = 15 + for i in range(num_range): + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) + self.nodes[0].generate(1) + nBlocks += 1 + self.sync_all() + + for i in range(num_range): + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) + self.nodes[0].generate(1) + nBlocks += 1 + self.sync_all() + + for i in range(num_range): + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) + self.nodes[0].generate(1) + nBlocks += 1 + self.sync_all() + + stop_nodes(self.nodes) + wait_bitcoinds() + + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-reindex", "-checkblockindex=1"])) + i = 0 + while (i < 10): + if (self.nodes[0].getblockcount() == nBlocks): + break + i += 1 + time.sleep(1) + assert_equal(self.nodes[0].getblockcount(), nBlocks) + + print("Success") + +if __name__ == '__main__': + ReindexTest().main() diff --git a/qa/rpc-tests/replace-by-fee.py b/qa/rpc-tests/replace-by-fee.py new file mode 100644 index 00000000..2238994f --- /dev/null +++ b/qa/rpc-tests/replace-by-fee.py @@ -0,0 +1,586 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test replace by fee code +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.script import * +from test_framework.mininode import * + +MAX_REPLACEMENT_LIMIT = 100 + +def txToHex(tx): + return bytes_to_hex_str(tx.serialize()) + +def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])): + """Create a txout with a given amount and scriptPubKey + + Mines coins as needed. + + confirmed - txouts created will be confirmed in the blockchain; + unconfirmed otherwise. + """ + fee = 1*COIN + while node.getbalance() < satoshi_round((amount + fee)/COIN): + node.generate(100) + #print (node.getbalance(), amount, fee) + + new_addr = node.getnewaddress() + #print new_addr + txid = node.sendtoaddress(new_addr, satoshi_round((amount+fee)/COIN)) + tx1 = node.getrawtransaction(txid, 1) + txid = int(txid, 16) + i = None + + for i, txout in enumerate(tx1['vout']): + #print i, txout['scriptPubKey']['addresses'] + if txout['scriptPubKey']['addresses'] == [new_addr]: + #print i + break + assert i is not None + + tx2 = CTransaction() + tx2.vin = [CTxIn(COutPoint(txid, i))] + tx2.vout = [CTxOut(amount, scriptPubKey)] + tx2.rehash() + + signed_tx = node.signrawtransaction(txToHex(tx2)) + + txid = node.sendrawtransaction(signed_tx['hex'], True) + + # If requested, ensure txouts are confirmed. + if confirmed: + mempool_size = len(node.getrawmempool()) + while mempool_size > 0: + node.generate(1) + new_size = len(node.getrawmempool()) + # Error out if we have something stuck in the mempool, as this + # would likely be a bug. + assert(new_size < mempool_size) + mempool_size = new_size + + return COutPoint(int(txid, 16), 0) + +class ReplaceByFeeTest(BitcoinTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug", + "-relaypriority=0", "-whitelist=127.0.0.1", + "-limitancestorcount=50", + "-limitancestorsize=101", + "-limitdescendantcount=200", + "-limitdescendantsize=101" + ])) + self.is_network_split = False + + def run_test(self): + make_utxo(self.nodes[0], 1*COIN) + + print("Running test simple doublespend...") + self.test_simple_doublespend() + + print("Running test doublespend chain...") + self.test_doublespend_chain() + + print("Running test doublespend tree...") + self.test_doublespend_tree() + + print("Running test replacement feeperkb...") + self.test_replacement_feeperkb() + + print("Running test spends of conflicting outputs...") + self.test_spends_of_conflicting_outputs() + + print("Running test new unconfirmed inputs...") + self.test_new_unconfirmed_inputs() + + print("Running test too many replacements...") + self.test_too_many_replacements() + + print("Running test opt-in...") + self.test_opt_in() + + print("Running test prioritised transactions...") + self.test_prioritised_transactions() + + print("Passed\n") + + def test_simple_doublespend(self): + """Simple doublespend""" + tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + + tx1a = CTransaction() + tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx1a_hex = txToHex(tx1a) + tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + + # Should fail because we haven't changed the fee + tx1b = CTransaction() + tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1b.vout = [CTxOut(1*COIN, CScript([b'b']))] + tx1b_hex = txToHex(tx1b) + + try: + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) # insufficient fee + else: + assert(False) + + # Extra 0.1 BTC fee + tx1b = CTransaction() + tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))] + tx1b_hex = txToHex(tx1b) + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + + mempool = self.nodes[0].getrawmempool() + + assert (tx1a_txid not in mempool) + assert (tx1b_txid in mempool) + + assert_equal(tx1b_hex, self.nodes[0].getrawtransaction(tx1b_txid)) + + def test_doublespend_chain(self): + """Doublespend of a long chain""" + + initial_nValue = 50*COIN + tx0_outpoint = make_utxo(self.nodes[0], initial_nValue) + + prevout = tx0_outpoint + remaining_value = initial_nValue + chain_txids = [] + while remaining_value > 10*COIN: + remaining_value -= 1*COIN + tx = CTransaction() + tx.vin = [CTxIn(prevout, nSequence=0)] + tx.vout = [CTxOut(remaining_value, CScript([1]))] + tx_hex = txToHex(tx) + txid = self.nodes[0].sendrawtransaction(tx_hex, True) + chain_txids.append(txid) + prevout = COutPoint(int(txid, 16), 0) + + # Whether the double-spend is allowed is evaluated by including all + # child fees - 40 BTC - so this attempt is rejected. + dbl_tx = CTransaction() + dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)] + dbl_tx.vout = [CTxOut(initial_nValue - 30*COIN, CScript([1]))] + dbl_tx_hex = txToHex(dbl_tx) + + try: + self.nodes[0].sendrawtransaction(dbl_tx_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) # insufficient fee + else: + assert(False) # transaction mistakenly accepted! + + # Accepted with sufficient fee + dbl_tx = CTransaction() + dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)] + dbl_tx.vout = [CTxOut(1*COIN, CScript([1]))] + dbl_tx_hex = txToHex(dbl_tx) + self.nodes[0].sendrawtransaction(dbl_tx_hex, True) + + mempool = self.nodes[0].getrawmempool() + for doublespent_txid in chain_txids: + assert(doublespent_txid not in mempool) + + def test_doublespend_tree(self): + """Doublespend of a big tree of transactions""" + + initial_nValue = 50*COIN + tx0_outpoint = make_utxo(self.nodes[0], initial_nValue) + + def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _total_txs=None): + if _total_txs is None: + _total_txs = [0] + if _total_txs[0] >= max_txs: + return + + txout_value = (initial_value - fee) // tree_width + if txout_value < fee: + return + + vout = [CTxOut(txout_value, CScript([i+1])) + for i in range(tree_width)] + tx = CTransaction() + tx.vin = [CTxIn(prevout, nSequence=0)] + tx.vout = vout + tx_hex = txToHex(tx) + + assert(len(tx.serialize()) < 100000) + txid = self.nodes[0].sendrawtransaction(tx_hex, True) + yield tx + _total_txs[0] += 1 + + txid = int(txid, 16) + + for i, txout in enumerate(tx.vout): + for x in branch(COutPoint(txid, i), txout_value, + max_txs, + tree_width=tree_width, fee=fee, + _total_txs=_total_txs): + yield x + + fee = int(0.0001*COIN) + n = MAX_REPLACEMENT_LIMIT + tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee)) + assert_equal(len(tree_txs), n) + + # Attempt double-spend, will fail because too little fee paid + dbl_tx = CTransaction() + dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)] + dbl_tx.vout = [CTxOut(initial_nValue - fee*n, CScript([1]))] + dbl_tx_hex = txToHex(dbl_tx) + try: + self.nodes[0].sendrawtransaction(dbl_tx_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) # insufficient fee + else: + assert(False) + + # 1 BTC fee is enough + dbl_tx = CTransaction() + dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)] + dbl_tx.vout = [CTxOut(initial_nValue - fee*n - 1*COIN, CScript([1]))] + dbl_tx_hex = txToHex(dbl_tx) + self.nodes[0].sendrawtransaction(dbl_tx_hex, True) + + mempool = self.nodes[0].getrawmempool() + + for tx in tree_txs: + tx.rehash() + assert (tx.hash not in mempool) + + # Try again, but with more total transactions than the "max txs + # double-spent at once" anti-DoS limit. + for n in (MAX_REPLACEMENT_LIMIT+1, MAX_REPLACEMENT_LIMIT*2): + fee = int(0.0001*COIN) + tx0_outpoint = make_utxo(self.nodes[0], initial_nValue) + tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee)) + assert_equal(len(tree_txs), n) + + dbl_tx = CTransaction() + dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)] + dbl_tx.vout = [CTxOut(initial_nValue - 2*fee*n, CScript([1]))] + dbl_tx_hex = txToHex(dbl_tx) + try: + self.nodes[0].sendrawtransaction(dbl_tx_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + assert_equal("too many potential replacements" in exp.error['message'], True) + else: + assert(False) + + for tx in tree_txs: + tx.rehash() + self.nodes[0].getrawtransaction(tx.hash) + + def test_replacement_feeperkb(self): + """Replacement requires fee-per-KB to be higher""" + tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + + tx1a = CTransaction() + tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx1a_hex = txToHex(tx1a) + tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + + # Higher fee, but the fee per KB is much lower, so the replacement is + # rejected. + tx1b = CTransaction() + tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*999000]))] + tx1b_hex = txToHex(tx1b) + + try: + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) # insufficient fee + else: + assert(False) + + def test_spends_of_conflicting_outputs(self): + """Replacements that spend conflicting tx outputs are rejected""" + utxo1 = make_utxo(self.nodes[0], int(1.2*COIN)) + utxo2 = make_utxo(self.nodes[0], 3*COIN) + + tx1a = CTransaction() + tx1a.vin = [CTxIn(utxo1, nSequence=0)] + tx1a.vout = [CTxOut(int(1.1*COIN), CScript([b'a']))] + tx1a_hex = txToHex(tx1a) + tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + + tx1a_txid = int(tx1a_txid, 16) + + # Direct spend an output of the transaction we're replacing. + tx2 = CTransaction() + tx2.vin = [CTxIn(utxo1, nSequence=0), CTxIn(utxo2, nSequence=0)] + tx2.vin.append(CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)) + tx2.vout = tx1a.vout + tx2_hex = txToHex(tx2) + + try: + tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + assert(False) + + # Spend tx1a's output to test the indirect case. + tx1b = CTransaction() + tx1b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)] + tx1b.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx1b_hex = txToHex(tx1b) + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + tx1b_txid = int(tx1b_txid, 16) + + tx2 = CTransaction() + tx2.vin = [CTxIn(utxo1, nSequence=0), CTxIn(utxo2, nSequence=0), + CTxIn(COutPoint(tx1b_txid, 0))] + tx2.vout = tx1a.vout + tx2_hex = txToHex(tx2) + + try: + tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + assert(False) + + def test_new_unconfirmed_inputs(self): + """Replacements that add new unconfirmed inputs are rejected""" + confirmed_utxo = make_utxo(self.nodes[0], int(1.1*COIN)) + unconfirmed_utxo = make_utxo(self.nodes[0], int(0.1*COIN), False) + + tx1 = CTransaction() + tx1.vin = [CTxIn(confirmed_utxo)] + tx1.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx1_hex = txToHex(tx1) + tx1_txid = self.nodes[0].sendrawtransaction(tx1_hex, True) + + tx2 = CTransaction() + tx2.vin = [CTxIn(confirmed_utxo), CTxIn(unconfirmed_utxo)] + tx2.vout = tx1.vout + tx2_hex = txToHex(tx2) + + try: + tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + assert(False) + + def test_too_many_replacements(self): + """Replacements that evict too many transactions are rejected""" + # Try directly replacing more than MAX_REPLACEMENT_LIMIT + # transactions + + # Start by creating a single transaction with many outputs + initial_nValue = 10*COIN + utxo = make_utxo(self.nodes[0], initial_nValue) + fee = int(0.0001*COIN) + split_value = int((initial_nValue-fee)/(MAX_REPLACEMENT_LIMIT+1)) + actual_fee = initial_nValue - split_value*(MAX_REPLACEMENT_LIMIT+1) + + outputs = [] + for i in range(MAX_REPLACEMENT_LIMIT+1): + outputs.append(CTxOut(split_value, CScript([1]))) + + splitting_tx = CTransaction() + splitting_tx.vin = [CTxIn(utxo, nSequence=0)] + splitting_tx.vout = outputs + splitting_tx_hex = txToHex(splitting_tx) + + txid = self.nodes[0].sendrawtransaction(splitting_tx_hex, True) + txid = int(txid, 16) + + # Now spend each of those outputs individually + for i in range(MAX_REPLACEMENT_LIMIT+1): + tx_i = CTransaction() + tx_i.vin = [CTxIn(COutPoint(txid, i), nSequence=0)] + tx_i.vout = [CTxOut(split_value-fee, CScript([b'a']))] + tx_i_hex = txToHex(tx_i) + self.nodes[0].sendrawtransaction(tx_i_hex, True) + + # Now create doublespend of the whole lot; should fail. + # Need a big enough fee to cover all spending transactions and have + # a higher fee rate + double_spend_value = (split_value-100*fee)*(MAX_REPLACEMENT_LIMIT+1) + inputs = [] + for i in range(MAX_REPLACEMENT_LIMIT+1): + inputs.append(CTxIn(COutPoint(txid, i), nSequence=0)) + double_tx = CTransaction() + double_tx.vin = inputs + double_tx.vout = [CTxOut(double_spend_value, CScript([b'a']))] + double_tx_hex = txToHex(double_tx) + + try: + self.nodes[0].sendrawtransaction(double_tx_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + assert_equal("too many potential replacements" in exp.error['message'], True) + else: + assert(False) + + # If we remove an input, it should pass + double_tx = CTransaction() + double_tx.vin = inputs[0:-1] + double_tx.vout = [CTxOut(double_spend_value, CScript([b'a']))] + double_tx_hex = txToHex(double_tx) + self.nodes[0].sendrawtransaction(double_tx_hex, True) + + def test_opt_in(self): + """ Replacing should only work if orig tx opted in """ + tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + + # Create a non-opting in transaction + tx1a = CTransaction() + tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0xffffffff)] + tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx1a_hex = txToHex(tx1a) + tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + + # Shouldn't be able to double-spend + tx1b = CTransaction() + tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))] + tx1b_hex = txToHex(tx1b) + + try: + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + print(tx1b_txid) + assert(False) + + tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + + # Create a different non-opting in transaction + tx2a = CTransaction() + tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0xfffffffe)] + tx2a.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx2a_hex = txToHex(tx2a) + tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, True) + + # Still shouldn't be able to double-spend + tx2b = CTransaction() + tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)] + tx2b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))] + tx2b_hex = txToHex(tx2b) + + try: + tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + assert(False) + + # Now create a new transaction that spends from tx1a and tx2a + # opt-in on one of the inputs + # Transaction should be replaceable on either input + + tx1a_txid = int(tx1a_txid, 16) + tx2a_txid = int(tx2a_txid, 16) + + tx3a = CTransaction() + tx3a.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0xffffffff), + CTxIn(COutPoint(tx2a_txid, 0), nSequence=0xfffffffd)] + tx3a.vout = [CTxOut(int(0.9*COIN), CScript([b'c'])), CTxOut(int(0.9*COIN), CScript([b'd']))] + tx3a_hex = txToHex(tx3a) + + self.nodes[0].sendrawtransaction(tx3a_hex, True) + + tx3b = CTransaction() + tx3b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)] + tx3b.vout = [CTxOut(int(0.5*COIN), CScript([b'e']))] + tx3b_hex = txToHex(tx3b) + + tx3c = CTransaction() + tx3c.vin = [CTxIn(COutPoint(tx2a_txid, 0), nSequence=0)] + tx3c.vout = [CTxOut(int(0.5*COIN), CScript([b'f']))] + tx3c_hex = txToHex(tx3c) + + self.nodes[0].sendrawtransaction(tx3b_hex, True) + # If tx3b was accepted, tx3c won't look like a replacement, + # but make sure it is accepted anyway + self.nodes[0].sendrawtransaction(tx3c_hex, True) + + def test_prioritised_transactions(self): + # Ensure that fee deltas used via prioritisetransaction are + # correctly used by replacement logic + + # 1. Check that feeperkb uses modified fees + tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + + tx1a = CTransaction() + tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx1a_hex = txToHex(tx1a) + tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + + # Higher fee, but the actual fee per KB is much lower. + tx1b = CTransaction() + tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*740000]))] + tx1b_hex = txToHex(tx1b) + + # Verify tx1b cannot replace tx1a. + try: + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + assert(False) + + # Use prioritisetransaction to set tx1a's fee to 0. + self.nodes[0].prioritisetransaction(tx1a_txid, 0, int(-0.1*COIN)) + + # Now tx1b should be able to replace tx1a + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + + assert(tx1b_txid in self.nodes[0].getrawmempool()) + + # 2. Check that absolute fee checks use modified fee. + tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + + tx2a = CTransaction() + tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0)] + tx2a.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx2a_hex = txToHex(tx2a) + tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, True) + + # Lower fee, but we'll prioritise it + tx2b = CTransaction() + tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)] + tx2b.vout = [CTxOut(int(1.01*COIN), CScript([b'a']))] + tx2b.rehash() + tx2b_hex = txToHex(tx2b) + + # Verify tx2b cannot replace tx2a. + try: + tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + assert(False) + + # Now prioritise tx2b to have a higher modified fee + self.nodes[0].prioritisetransaction(tx2b.hash, 0, int(0.1*COIN)) + + # tx2b should now be accepted + tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True) + + assert(tx2b_txid in self.nodes[0].getrawmempool()) + +if __name__ == '__main__': + ReplaceByFeeTest().main() diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py new file mode 100644 index 00000000..e31df3d1 --- /dev/null +++ b/qa/rpc-tests/rest.py @@ -0,0 +1,335 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test REST interface +# + + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from struct import * +from io import BytesIO +from codecs import encode + +import http.client +import urllib.parse + +def deser_uint256(f): + r = 0 + for i in range(8): + t = unpack(b" 0: + with mininode_lock: + self.block_announced = False + + success = True + compare_inv = [] + if self.last_inv != []: + all_inv = [x.inv for x in self.last_inv] + for x in all_inv: + test_inv = [y.hash for y in x] + compare_inv = compare_inv + test_inv + + #Check whether the inventory received is within the list of block hashes that were + #mined (During a large reorg the inv's will be fewer than the actual hashes mined). + s = set(compare_inv) + expect_inv = [x for x in expect_inv if x in s] + if compare_inv != expect_inv: + success = False + + hash_headers = [] + if self.last_headers != None: + # treat headers as a list of block hashes + hash_headers = [ x.sha256 for x in self.last_headers.headers ] + if hash_headers != expect_headers: + success = False + + self.last_inv = [] + self.last_headers = None + + if success == True: + return success + + time.sleep(self.sleep_time) + timeout -= self.sleep_time + + # Syncing helpers + def sync(self, test_function, timeout=60): + while timeout > 0: + with mininode_lock: + if test_function(): + return + + time.sleep(self.sleep_time) + timeout -= self.sleep_time + raise AssertionError("Sync failed to complete") + + # The request manager does not deal with vectors of GETDATA requests but rather one GETDATA per + # hash, therefore we need to be able to sync_getdata one message at a time rather than in batches. + def sync_getdata(self, hash_list, timeout=60): + while timeout > 0: + with mininode_lock: + #Check whether any getdata responses are in the hash list and + #if so remove them from both lists. + for x in self.last_getdata: + for y in hash_list: + if (str(x.inv).find(hex(y)[2:]) > 0): + self.last_getdata.remove(x) + hash_list.remove(y) + if hash_list == []: + return + + time.sleep(self.sleep_time) + timeout -= self.sleep_time + raise AssertionError("Sync getdata failed to complete") + + def sync_with_ping(self, timeout=60): + self.send_message(msg_ping(nonce=self.ping_counter)) + test_function = lambda: self.last_pong.nonce == self.ping_counter + self.sync(test_function, timeout) + self.ping_counter += 1 + return + + def wait_for_block(self, blockhash, timeout=60): + test_function = lambda: self.last_block != None and self.last_block.sha256 == blockhash + self.sync(test_function, timeout) + return + + def wait_for_getheaders(self, timeout=60): + test_function = lambda: self.last_getheaders != None + self.sync(test_function, timeout) + return + + def wait_for_getdata(self, hash_list, timeout=60): + if hash_list == []: + return + + self.sync_getdata(hash_list, timeout) + return + + def wait_for_disconnect(self, timeout=60): + test_function = lambda: self.disconnected + self.sync(test_function, timeout) + return + + def send_header_for_blocks(self, new_blocks): + headers_message = msg_headers() + headers_message.headers = [ CBlockHeader(b) for b in new_blocks ] + self.send_message(headers_message) + + def send_getblocks(self, locator): + getblocks_message = msg_getblocks() + getblocks_message.locator.vHave = locator + self.send_message(getblocks_message) + +# InvNode: This peer should only ever receive inv's, because it doesn't ever send a +# "sendheaders" message. +class InvNode(BaseNode): + def __init__(self): + BaseNode.__init__(self) + +# TestNode: This peer is the one we use for most of the testing. +class TestNode(BaseNode): + def __init__(self): + BaseNode.__init__(self) + +class SendHeadersTest(BitcoinTestFramework): + def setup_chain(self): + initialize_chain_clean(self.options.tmpdir, 2) + + def setup_network(self): + # TODO: currently mininode does not have support for thinblocks so we can not sync a get_xthin request and must + # therefore have thinblocks turned off during testing. + # Currently there are mininode syncronization issues when Parallel Validation is turned on + # and therefore have -parallel=0 when running these tests. + self.nodes = [] + self.nodes = start_nodes(2, self.options.tmpdir, [["-debug", "-logtimemicros=1", "-parallel=0", "-use-thinblocks=0"]]*2) + connect_nodes(self.nodes[0], 1) + + # mine count blocks and return the new tip + def mine_blocks(self, count): + # Clear out last block announcement from each p2p listener + [ x.clear_last_announcement() for x in self.p2p_connections ] + self.nodes[0].generate(count) + return int(self.nodes[0].getbestblockhash(), 16) + + # mine a reorg that invalidates length blocks (replacing them with + # length+1 blocks). + # Note: we clear the state of our p2p connections after the + # to-be-reorged-out blocks are mined, so that we don't break later tests. + # return the list of block hashes newly mined + def mine_reorg(self, length): + self.nodes[0].generate(length) # make sure all invalidated blocks are node0's + sync_blocks(self.nodes, wait=0.1) + [x.clear_last_announcement() for x in self.p2p_connections] + + tip_height = self.nodes[1].getblockcount() + hash_to_invalidate = self.nodes[1].getblockhash(tip_height-(length-1)) + self.nodes[1].invalidateblock(hash_to_invalidate) + all_hashes = self.nodes[1].generate(length+1) # Must be longer than the orig chain + sync_blocks(self.nodes, wait=0.1) + return [int(x, 16) for x in all_hashes] + + def run_test(self): + + # Set the forktime to be far into the future. Running the sript after forktime will cause a failure since + # we will be expecting a > 1MB block to begin with. + self.nodes[0].set("mining.forkTime=1901590000") + self.nodes[1].set("mining.forkTime=1901590000") + + # Setup the p2p connections and start up the network thread. + inv_node = InvNode() + test_node = TestNode() + + self.p2p_connections = [inv_node, test_node] + + connections = [] + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], inv_node)) + # Set nServices to 0 for test_node, so no block download will occur outside of + # direct fetching + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node, services=0)) + inv_node.add_connection(connections[0]) + test_node.add_connection(connections[1]) + + NetworkThread().start() # Start up network handling in another thread + + # Test logic begins here + inv_node.wait_for_verack() + test_node.wait_for_verack() + + tip = int(self.nodes[0].getbestblockhash(), 16) + + # PART 1 + # 1. Mine a block; expect inv announcements each time + print("Part 1: headers don't start before sendheaders message...") + for i in range(4): + old_tip = tip + tip = self.mine_blocks(1) + assert_equal(inv_node.check_last_announcement(inv=[tip]), True) + assert_equal(test_node.check_last_announcement(inv=[tip]), True) + # Try a few different responses; none should affect next announcement + if i == 0: + # first request the block + test_node.get_data([tip]) + test_node.wait_for_block(tip, timeout=5) + elif i == 1: + # next try requesting header and block + test_node.get_headers(locator=[old_tip], hashstop=tip) + test_node.get_data([tip]) + test_node.wait_for_block(tip) + test_node.clear_last_announcement() # since we requested headers... + elif i == 2: + # this time announce own block via headers + height = self.nodes[0].getblockcount() + last_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + block_time = last_time + 1 + new_block = create_block(tip, create_coinbase(height+1), block_time) + new_block.solve() + test_node.send_header_for_blocks([new_block]) + test_node.wait_for_getdata([new_block.sha256], timeout=5) + test_node.send_message(msg_block(new_block)) + test_node.sync_with_ping() # make sure this block is processed + inv_node.clear_last_announcement() + test_node.clear_last_announcement() + + print("Part 1: success!") + print("Part 2: announce blocks with headers after sendheaders message...") + # PART 2 + # 2. Send a sendheaders message and test that headers announcements + # commence and keep working. + test_node.send_message(msg_sendheaders()) + prev_tip = int(self.nodes[0].getbestblockhash(), 16) + test_node.get_headers(locator=[prev_tip], hashstop=0) + test_node.sync_with_ping() + + # Now that we've synced headers, headers announcements should work + tip = self.mine_blocks(1) + assert_equal(inv_node.check_last_announcement(inv=[tip]), True) + assert_equal(test_node.check_last_announcement(headers=[tip]), True) + + height = self.nodes[0].getblockcount()+1 + block_time += 10 # Advance far enough ahead + for i in range(10): + # Mine i blocks, and alternate announcing either via + # inv (of tip) or via headers. After each, new blocks + # mined by the node should successfully be announced + # with block header, even though the blocks are never requested + for j in range(2): + blocks = [] + for b in range(1): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + if j == 0: + # Announce via inv + test_node.send_block_inv(tip) + test_node.wait_for_getheaders() + test_node.send_header_for_blocks(blocks) + test_node.wait_for_getdata([tip], timeout=5) + # Test that duplicate inv's won't result in duplicate + # getdata requests, or duplicate headers announcements + inv_node.send_block_inv(tip) + # Should have received a getheaders as well! + test_node.send_header_for_blocks(blocks) + test_node.sync_with_ping() + test_node.wait_for_getdata([x.sha256 for x in blocks[0:-1]], timeout=5) + [ inv_node.send_block_inv(x.sha256) for x in blocks[0:-1] ] + inv_node.sync_with_ping() + else: + # Announce via headers + test_node.send_header_for_blocks(blocks) + test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=5) + # Test that duplicate headers won't result in duplicate + # getdata requests (the check is further down) + inv_node.send_header_for_blocks(blocks) + inv_node.sync_with_ping() + [ test_node.send_message(msg_block(x)) for x in blocks ] + test_node.sync_with_ping() + inv_node.sync_with_ping() + # This block should not be announced to the inv node (since it also + # broadcast it) + assert_equal(inv_node.last_inv, []) + assert_equal(inv_node.last_headers, None) + tip = self.mine_blocks(1) + assert_equal(inv_node.check_last_announcement(inv=[tip]), True) + assert_equal(test_node.check_last_announcement(headers=[tip]), True) + height += 1 + block_time += 1 + + print("Part 2: success!") + + print("Part 3: headers announcements can stop after large reorg, and resume after headers/inv from peer...") + + # PART 3. Headers announcements can stop after large reorg, and resume after + # getheaders or inv from peer. + for j in range(2): + # First try mining a reorg that can propagate with header announcement + new_block_hashes = self.mine_reorg(length=7) + assert_equal(inv_node.check_last_announcement(inv=new_block_hashes), True) + assert_equal(test_node.check_last_announcement(headers=new_block_hashes), True) + + block_time += 8 + + # Mine a too-large reorg - we will receive only the first 8 inv's for the 9 block hashes mined. + # which represents the MAX_BLOCKS_TO_ANNOUNCE=8 + new_block_hashes = self.mine_reorg(length=8) + tip = new_block_hashes[-1] + assert_equal(inv_node.check_last_announcement(inv=new_block_hashes), True) + assert_equal(test_node.check_last_announcement(inv=new_block_hashes), True) + + block_time += 9 + + fork_point = self.nodes[0].getblock("%02x" % new_block_hashes[0])["previousblockhash"] + fork_point = int(fork_point, 16) + + # Use getblocks/getdata + test_node.send_getblocks(locator = [fork_point]) + assert_equal(test_node.check_last_announcement(inv=new_block_hashes), True) + test_node.get_data(new_block_hashes) + test_node.wait_for_block(new_block_hashes[-1]) + + for i in range(3): + # Mine another block, still should get only an inv + tip = self.mine_blocks(1) + assert_equal(inv_node.check_last_announcement(inv=[tip]), True) + assert_equal(test_node.check_last_announcement(inv=[tip]), True) + if i == 0: + # Just get the data -- shouldn't cause headers announcements to resume + test_node.get_data([tip]) + test_node.wait_for_block(tip) + elif i == 1: + # Send a getheaders message that shouldn't trigger headers announcements + # to resume (best header sent will be too old) + test_node.get_headers(locator=[fork_point], hashstop=new_block_hashes[1]) + test_node.get_data([tip]) + test_node.wait_for_block(tip) + elif i == 2: + test_node.get_data([tip]) + test_node.wait_for_block(tip) + # This time, try sending either a getheaders to trigger resumption + # of headers announcements, or mine a new block and inv it, also + # triggering resumption of headers announcements. + if j == 0: + test_node.get_headers(locator=[tip], hashstop=0) + test_node.sync_with_ping() + else: + test_node.send_block_inv(tip) + test_node.sync_with_ping() + # New blocks should now be announced with header + tip = self.mine_blocks(1) + assert_equal(inv_node.check_last_announcement(inv=[tip]), True) + assert_equal(test_node.check_last_announcement(headers=[tip]), True) + + print("Part 3: success!") + + print("Part 4: Testing direct fetch behavior...") + tip = self.mine_blocks(1) + height = self.nodes[0].getblockcount() + 1 + last_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + block_time = last_time + 1 + + # Create 2 blocks. Send the blocks, then send the headers. + blocks = [] + for b in range(2): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + inv_node.send_message(msg_block(blocks[-1])) + + inv_node.sync_with_ping() # Make sure blocks are processed + test_node.last_getdata = [] + test_node.send_header_for_blocks(blocks) + test_node.sync_with_ping() + # should not have received any getdata messages + with mininode_lock: + assert_equal(test_node.last_getdata, []) + + # This time, direct fetch should work + blocks = [] + for b in range(3): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + + test_node.send_header_for_blocks(blocks) + test_node.sync_with_ping() + test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=5) + + [ test_node.send_message(msg_block(x)) for x in blocks ] + + test_node.sync_with_ping() + + # Now announce a header that forks the last two blocks + tip = blocks[0].sha256 + height -= 1 + blocks = [] + + # Create extra blocks for later + for b in range(20): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + + # Announcing one block on fork should not trigger direct fetch + # (less work than tip) + test_node.last_getdata = [] + test_node.send_header_for_blocks(blocks[0:1]) + test_node.sync_with_ping() + with mininode_lock: + assert_equal(test_node.last_getdata, []) + + # Announcing one more block on fork should trigger direct fetch for + # both blocks (same work as tip) + test_node.send_header_for_blocks(blocks[1:2]) + test_node.sync_with_ping() + test_node.wait_for_getdata([x.sha256 for x in blocks[0:2]], timeout=5) + + # Announcing 16 more headers should trigger direct fetch for 14 more + # blocks + self.nodes[0].set("net.maxBlocksInTransitPerPeer=16") + self.nodes[1].set("net.maxBlocksInTransitPerPeer=16") + test_node.send_header_for_blocks(blocks[2:18]) + test_node.sync_with_ping() + test_node.wait_for_getdata([x.sha256 for x in blocks[2:16]], timeout=5) + with mininode_lock: + assert_equal(test_node.last_getdata, []) + + # Announcing 1 more header should not trigger any response because we + # already have the maximumum blocks in flight + test_node.last_getdata = [] + test_node.send_header_for_blocks(blocks[18:19]) + test_node.sync_with_ping() + with mininode_lock: + assert_equal(test_node.last_getdata, []) + + print("Part 4: success!") + + # Now deliver all those blocks we announced. + [ test_node.send_message(msg_block(x)) for x in blocks ] + + print("Part 5: Testing handling of unconnecting headers") + # Test1: We test that receipt of a single unconnecting header doesn't cause a problem + # Send an out of order header. Then send both headers in the correct order. + # Result: Block chain updates correctly. + for i in range(2): + test_node.last_getdata = [] + blocks = [] + # Create two more blocks. + for j in range(2): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + + # Send the header of the second block -> this won't connect. + test_node.send_header_for_blocks([blocks[1]]) + test_node.sync_with_ping() + assert_not_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[1].sha256) + + # Now send them in the right order + test_node.send_header_for_blocks(blocks) + test_node.sync_with_ping() + + # Wait for getdata and send blocks + test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=5) + [ test_node.send_message(msg_block(x)) for x in blocks ] + test_node.sync_with_ping() + + # Block chain should have updated correctly and all blocks connected + assert_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[1].sha256) + + # Test2: We test that receipt of a single unconnecting header doesn't cause a problem + # Send an out of order header. Then send the first header. + # Result: Block chain updates correctly. + for i in range(2): + test_node.last_getdata = [] + blocks = [] + # Create two more blocks. + for j in range(2): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + + # Send the header of the second block -> this won't connect. + test_node.send_header_for_blocks([blocks[1]]) + test_node.sync_with_ping() + assert_not_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[1].sha256) + + # Now send the first header only + test_node.send_header_for_blocks([blocks[0]]) + test_node.sync_with_ping() + + # Wait for getdata and send blocks + test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=5) + [ test_node.send_message(msg_block(x)) for x in blocks ] + test_node.sync_with_ping() + + # Block chain should have updated correctly and all blocks connected + assert_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[1].sha256) + + # Test3: We test that receipt of a multiple unconnecting header doesn't cause a problem + # Send several out of order headers. Then send ALL the missing headers in order. + # Result: Block chain updates correctly. + for i in range(2): + test_node.last_getdata = [] + blocks = [] + # Create two more blocks. + for j in range(5): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + + # Reverse order of one of the blocks + blocks_reverse = [] + if i == 0: + blocks_reverse.append(blocks[1]) + blocks_reverse.append(blocks[0]) + blocks_reverse.append(blocks[2]) + blocks_reverse.append(blocks[3]) + blocks_reverse.append(blocks[4]) + + if i == 1: + blocks_reverse.append(blocks[0]) + blocks_reverse.append(blocks[1]) + blocks_reverse.append(blocks[2]) + blocks_reverse.append(blocks[4]) + blocks_reverse.append(blocks[3]) + + # Send the header of the second block out of order-> this won't connect. + test_node.send_header_for_blocks(blocks_reverse) + test_node.sync_with_ping() + assert_not_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[4].sha256) + + # Now send them in the right order + test_node.send_header_for_blocks(blocks) + test_node.sync_with_ping() + + # Wait for getdata and send blocks + test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=5) + [ test_node.send_message(msg_block(x)) for x in blocks ] + test_node.sync_with_ping() + + # Block chain should have updated correctly and all blocks connected + assert_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[4].sha256) + + # Test4: We test that receipt of a multiple unconnecting header doesn't cause a problem + # Send several out of order headers. Then send only the missing header. + # Result: Block chain updates correctly. + for i in range(1): + test_node.last_getdata = [] + blocks = [] + # Create two more blocks. + for j in range(5): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + + # Reverse order of one of the blocks + blocks_reverse = [] + if i == 0: + blocks_reverse.append(blocks[1]) + blocks_reverse.append(blocks[0]) + blocks_reverse.append(blocks[2]) + blocks_reverse.append(blocks[3]) + blocks_reverse.append(blocks[4]) + + # Send the header of the second block -> this won't connect. + test_node.send_header_for_blocks(blocks_reverse) + test_node.sync_with_ping() + assert_not_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[1].sha256) + + # Now send them in the right order + test_node.send_header_for_blocks([blocks[0]]) + test_node.sync_with_ping() + + # Wait for getdata and send blocks + test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=5) + [ test_node.send_message(msg_block(x)) for x in blocks ] + test_node.sync_with_ping() + + # Block chain should have updated correctly and all blocks connected + assert_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[4].sha256) + + # Test5: test that old unconnected headers will get deleted from the cache + # 1) Send and unconnecting header. + # Advance the time beyond the timeout. + # Send the first header. + # Result: both headers should connect. + # 2) Send an unconnecting header that is at height 3. + # Advance the time beyond the timeout. + # Send a second unconnecting header at height 2. + # Send the first header. + # Result: The first two headers should connected with the 3rd having been deleted and the + # chain will have only the first two blocks connected. + for i in range(2): + test_node.last_getdata = [] + blocks = [] + # Create two more blocks. + for j in range(2): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + + # Send the header of the second block -> this won't connect. + test_node.send_header_for_blocks([blocks[1]]) + test_node.sync_with_ping() + assert_not_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[1].sha256) + + # Advance the time beyond the timeout value + cur_time = int(time.time()) + self.nodes[0].setmocktime(cur_time + 120) + self.nodes[1].setmocktime(cur_time + 120) + + # Now send them in the right order + test_node.send_header_for_blocks([blocks[0]]) + test_node.sync_with_ping() + + # Wait for getdata and send blocks + test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=5) + [ test_node.send_message(msg_block(x)) for x in blocks ] + test_node.sync_with_ping() + + # Block chain should have updated correctly and all blocks connected + assert_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[1].sha256) + + for i in range(2): + test_node.last_getdata = [] + blocks = [] + # Create two more blocks. + for j in range(3): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + + self.nodes[0].setmocktime(block_time) + self.nodes[1].setmocktime(block_time) + + # Send the header of the third block -> this won't connect. + test_node.send_header_for_blocks([blocks[2]]) + test_node.sync_with_ping() + assert_not_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[2].sha256) + + #setting time to 120 seconds in the future will cause the unconnecting header to be deleted + self.nodes[0].setmocktime(block_time + 120) + self.nodes[1].setmocktime(block_time + 120) + + # Send the header of the second block -> this won't connect. + test_node.send_header_for_blocks([blocks[1]]) + test_node.sync_with_ping() + assert_not_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[1].sha256) + + # Now send the first header + test_node.send_header_for_blocks([blocks[0]]) + test_node.sync_with_ping() + + # Wait for getdata and send blocks + test_node.wait_for_getdata([x.sha256 for x in [blocks[0], blocks[1]]], timeout=5) + [ test_node.send_message(msg_block(x)) for x in [blocks[0], blocks[1]] ] + test_node.sync_with_ping() + + # Block chain should have updated correctly and all blocks connected to the second block + assert_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[1].sha256) + + # Send the header of the third block again -> this will connect. + test_node.send_header_for_blocks([blocks[2]]) + test_node.sync_with_ping() + + # Wait for getdata and send blocks + test_node.wait_for_getdata([x.sha256 for x in [blocks[2]]], timeout=5) + [ test_node.send_message(msg_block(x)) for x in [blocks[2]] ] + test_node.sync_with_ping() + + assert_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[2].sha256) + + # Send one more out of order header which should not cause any problems + test_node.last_getdata = [] + blocks = [] + # Create two more blocks + for j in range(2): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + # Send the header of the second block -> this won't connect. + test_node.send_header_for_blocks([blocks[1]]) + + # Finally, check that the inv node never received a getdata request, + # throughout the test + assert_equal(inv_node.last_getdata, []) + + print("Part 5: success!") + +if __name__ == '__main__': + SendHeadersTest().main() diff --git a/qa/rpc-tests/signrawtransactions.py b/qa/rpc-tests/signrawtransactions.py new file mode 100644 index 00000000..b76d00cb --- /dev/null +++ b/qa/rpc-tests/signrawtransactions.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + + +class SignRawTransactionsTest(BitcoinTestFramework): + """Tests transaction signing via RPC command "signrawtransaction".""" + + def setup_chain(self): + print('Initializing test directory ' + self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self, split=False): + self.nodes = start_nodes(1, self.options.tmpdir) + self.is_network_split = False + + def successful_signing_test(self): + """Creates and signs a valid raw transaction with one input. + + Expected results: + + 1) The transaction has a complete set of signatures + 2) No script verification error occurred""" + privKeys = ['cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N'] + + inputs = [ + # Valid pay-to-pubkey script + {'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 0, + 'scriptPubKey': '76a91460baa0f494b38ce3c940dea67f3804dc52d1fb9488ac', 'amount': 1.618} + ] + + outputs = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1} + + rawTx = self.nodes[0].createrawtransaction(inputs, outputs) + rawTxSigned = self.nodes[0].signrawtransaction(rawTx, inputs, privKeys) + + # 1) The transaction has a complete set of signatures + assert 'complete' in rawTxSigned + assert_equal(rawTxSigned['complete'], True) + + # 2) No script verification error occurred + assert 'errors' not in rawTxSigned + + def script_verification_error_test(self): + """Creates and signs a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script. + + Expected results: + + 3) The transaction has no complete set of signatures + 4) Two script verification errors occurred + 5) Script verification errors have certain properties ("txid", "vout", "scriptSig", "sequence", "error") + 6) The verification errors refer to the invalid (vin 1) and missing input (vin 2)""" + privKeys = ['cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N'] + + inputs = [ + # Valid pay-to-pubkey script + {'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 0}, + # Invalid script + {'txid': '5b8673686910442c644b1f4993d8f7753c7c8fcb5c87ee40d56eaeef25204547', 'vout': 7}, + # Missing scriptPubKey + {'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 1}, + ] + + scripts = [ + # Valid pay-to-pubkey script + {'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 0, 'amount':1.618, + 'scriptPubKey': '76a91460baa0f494b38ce3c940dea67f3804dc52d1fb9488ac'}, + # Invalid script + {'txid': '5b8673686910442c644b1f4993d8f7753c7c8fcb5c87ee40d56eaeef25204547', 'vout': 7, 'amount':1.618, + 'scriptPubKey': 'badbadbadbad'} + ] + + outputs = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1} + + rawTx = self.nodes[0].createrawtransaction(inputs, outputs) + rawTxSigned = self.nodes[0].signrawtransaction(rawTx, scripts, privKeys) + + # 3) The transaction has no complete set of signatures + assert 'complete' in rawTxSigned + assert_equal(rawTxSigned['complete'], False) + + # 4) Two script verification errors occurred + assert 'errors' in rawTxSigned + assert_equal(len(rawTxSigned['errors']), 2) + + # 5) Script verification errors have certain properties + assert 'txid' in rawTxSigned['errors'][0] + assert 'vout' in rawTxSigned['errors'][0] + assert 'scriptSig' in rawTxSigned['errors'][0] + assert 'sequence' in rawTxSigned['errors'][0] + assert 'error' in rawTxSigned['errors'][0] + + # 6) The verification errors refer to the invalid (vin 1) and missing input (vin 2) + assert_equal(rawTxSigned['errors'][0]['txid'], inputs[1]['txid']) + assert_equal(rawTxSigned['errors'][0]['vout'], inputs[1]['vout']) + assert_equal(rawTxSigned['errors'][1]['txid'], inputs[2]['txid']) + assert_equal(rawTxSigned['errors'][1]['vout'], inputs[2]['vout']) + + def run_test(self): + self.successful_signing_test() + self.script_verification_error_test() + + +if __name__ == '__main__': + SignRawTransactionsTest().main() + +def Test(): + t = SignRawTransactionsTest() + t.drop_to_pdb = True + bitcoinConf = { + "debug": ["net", "blk", "thin", "mempool", "req", "bench", "evict"], # "lck" + "blockprioritysize": 2000000 # we don't want any transactions rejected due to insufficient fees... + } + t.main(["--tmpdir=/ramdisk/test"], bitcoinConf, None) # , "--tracerpc"]) diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py new file mode 100644 index 00000000..55d0d39e --- /dev/null +++ b/qa/rpc-tests/smartfees.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test fee estimation code +# + +from collections import OrderedDict +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +# Construct 2 trivial P2SH's and the ScriptSigs that spend them +# So we can create many many transactions without needing to spend +# time signing. +P2SH_1 = "2MySexEGVzZpRgNQ1JdjdP5bRETznm3roQ2" # P2SH of "OP_1 OP_DROP" +P2SH_2 = "2NBdpwq8Aoo1EEKEXPNrKvr5xQr3M9UfcZA" # P2SH of "OP_2 OP_DROP" +# Associated ScriptSig's to spend satisfy P2SH_1 and P2SH_2 +# 4 bytes of OP_TRUE and push 2-byte redeem script of "OP_1 OP_DROP" or "OP_2 OP_DROP" +SCRIPT_SIG = ["0451025175", "0451025275"] + +def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee_increment): + ''' + Create and send a transaction with a random fee. + The transaction pays to a trivial P2SH script, and assumes that its inputs + are of the same form. + The function takes a list of confirmed outputs and unconfirmed outputs + and attempts to use the confirmed list first for its inputs. + It adds the newly created outputs to the unconfirmed list. + Returns (raw transaction, fee) + ''' + # It's best to exponentially distribute our random fees + # because the buckets are exponentially spaced. + # Exponentially distributed from 1-128 * fee_increment + rand_fee = float(fee_increment)*(1.1892**random.randint(0,28)) + # Total fee ranges from min_fee to min_fee + 127*fee_increment + fee = min_fee - fee_increment + satoshi_round(rand_fee) + inputs = [] + total_in = Decimal("0.00000000") + while total_in <= (amount + fee) and len(conflist) > 0: + t = conflist.pop(0) + total_in += t["amount"] + inputs.append({ "txid" : t["txid"], "vout" : t["vout"]} ) + if total_in <= amount + fee: + while total_in <= (amount + fee) and len(unconflist) > 0: + t = unconflist.pop(0) + total_in += t["amount"] + inputs.append({ "txid" : t["txid"], "vout" : t["vout"]} ) + if total_in <= amount + fee: + raise RuntimeError("Insufficient funds: need %d, have %d"%(amount+fee, total_in)) + outputs = {} + outputs = OrderedDict([(P2SH_1, total_in - amount - fee), + (P2SH_2, amount)]) + rawtx = from_node.createrawtransaction(inputs, outputs) + # createrawtransaction constructs a transaction that is ready to be signed. + # These transactions don't need to be signed, but we still have to insert the ScriptSig + # that will satisfy the ScriptPubKey. + completetx = rawtx[0:10] + inputnum = 0 + for inp in inputs: + completetx += rawtx[10+82*inputnum:82+82*inputnum] + completetx += SCRIPT_SIG[inp["vout"]] + completetx += rawtx[84+82*inputnum:92+82*inputnum] + inputnum += 1 + completetx += rawtx[10+82*inputnum:] + txid = from_node.sendrawtransaction(completetx, True) + unconflist.append({ "txid" : txid, "vout" : 0 , "amount" : total_in - amount - fee}) + unconflist.append({ "txid" : txid, "vout" : 1 , "amount" : amount}) + + return (completetx, fee) + +def split_inputs(from_node, txins, txouts, initial_split = False): + ''' + We need to generate a lot of very small inputs so we can generate a ton of transactions + and they will have low priority. + This function takes an input from txins, and creates and sends a transaction + which splits the value into 2 outputs which are appended to txouts. + ''' + prevtxout = txins.pop() + inputs = [] + inputs.append({ "txid" : prevtxout["txid"], "vout" : prevtxout["vout"] }) + half_change = satoshi_round(prevtxout["amount"]/2) + rem_change = prevtxout["amount"] - half_change - Decimal("0.00001000") + outputs = OrderedDict([(P2SH_1, half_change), (P2SH_2, rem_change)]) + rawtx = from_node.createrawtransaction(inputs, outputs) + # If this is the initial split we actually need to sign the transaction + # Otherwise we just need to insert the property ScriptSig + if (initial_split) : + completetx = from_node.signrawtransaction(rawtx)["hex"] + else : + completetx = rawtx[0:82] + SCRIPT_SIG[prevtxout["vout"]] + rawtx[84:] + txid = from_node.sendrawtransaction(completetx, True) + txouts.append({ "txid" : txid, "vout" : 0 , "amount" : half_change}) + txouts.append({ "txid" : txid, "vout" : 1 , "amount" : rem_change}) + +def check_estimates(node, fees_seen, max_invalid, print_estimates = True): + ''' + This function calls estimatefee and verifies that the estimates + meet certain invariants. + ''' + all_estimates = [ node.estimatefee(i) for i in range(1,26) ] + if print_estimates: + print([str(all_estimates[e-1]) for e in [1,2,3,6,15,25]]) + delta = 1.0e-6 # account for rounding error + last_e = max(fees_seen) + for e in [x for x in all_estimates if x >= 0]: + # Estimates should be within the bounds of what transactions fees actually were: + if float(e)+delta < min(fees_seen) or float(e)-delta > max(fees_seen): + raise AssertionError("Estimated fee (%f) out of range (%f,%f)" + %(float(e), min(fees_seen), max(fees_seen))) + # Estimates should be monotonically decreasing + if float(e)-delta > last_e: + raise AssertionError("Estimated fee (%f) larger than last fee (%f) for lower number of confirms" + %(float(e),float(last_e))) + last_e = e + valid_estimate = False + invalid_estimates = 0 + for i,e in enumerate(all_estimates): # estimate is for i+1 + if e >= 0: + valid_estimate = True + # estimatesmartfee should return the same result + assert_equal(node.estimatesmartfee(i+1)["feerate"], e) + + else: + invalid_estimates += 1 + + # estimatesmartfee should still be valid + approx_estimate = node.estimatesmartfee(i+1)["feerate"] + answer_found = node.estimatesmartfee(i+1)["blocks"] + assert(approx_estimate > 0) + assert(answer_found > i+1) + + # Once we're at a high enough confirmation count that we can give an estimate + # We should have estimates for all higher confirmation counts + if valid_estimate: + raise AssertionError("Invalid estimate appears at higher confirm count than valid estimate") + + # Check on the expected number of different confirmation counts + # that we might not have valid estimates for + if invalid_estimates > max_invalid: + raise AssertionError("More than (%d) invalid estimates"%(max_invalid)) + return all_estimates + + +class EstimateFeeTest(BitcoinTestFramework): + + def setup_network(self): + ''' + We'll setup the network to have 3 nodes that all mine with different parameters. + But first we need to use one node to create a lot of small low priority outputs + which we will use to generate our transactions. + ''' + self.nodes = [] + # Use node0 to mine blocks for input splitting + self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", + "-relaypriority=0", "-whitelist=127.0.0.1"])) + + print("This test is time consuming, please be patient") + print("Splitting inputs to small size so we can generate low priority tx's") + self.txouts = [] + self.txouts2 = [] + # Split a coinbase into two transaction puzzle outputs + split_inputs(self.nodes[0], self.nodes[0].listunspent(0), self.txouts, True) + + # Mine + while (len(self.nodes[0].getrawmempool()) > 0): + self.nodes[0].generate(1) + + # Repeatedly split those 2 outputs, doubling twice for each rep + # Use txouts to monitor the available utxo, since these won't be tracked in wallet + reps = 0 + while (reps < 5): + #Double txouts to txouts2 + while (len(self.txouts)>0): + split_inputs(self.nodes[0], self.txouts, self.txouts2) + while (len(self.nodes[0].getrawmempool()) > 0): + self.nodes[0].generate(1) + #Double txouts2 to txouts + while (len(self.txouts2)>0): + split_inputs(self.nodes[0], self.txouts2, self.txouts) + while (len(self.nodes[0].getrawmempool()) > 0): + self.nodes[0].generate(1) + reps += 1 + print("Finished splitting") + + # Now we can connect the other nodes, didn't want to connect them earlier + # so the estimates would not be affected by the splitting transactions + # Node1 mines small blocks but that are bigger than the expected transaction rate, + # and allows free transactions. + # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes, + # (17k is room enough for 110 or so transactions) + self.nodes.append(start_node(1, self.options.tmpdir, + ["-blockprioritysize=1500", "-blockmaxsize=17000", + "-maxorphantx=1000", "-relaypriority=0", "-debug=estimatefee"])) + connect_nodes(self.nodes[1], 0) + + # Node2 is a stingy miner, that + # produces too small blocks (room for only 55 or so transactions) + node2args = ["-blockprioritysize=0", "-blockmaxsize=8000", "-maxorphantx=1000", "-relaypriority=0"] + + self.nodes.append(start_node(2, self.options.tmpdir, node2args)) + connect_nodes(self.nodes[0], 2) + connect_nodes(self.nodes[2], 1) + + self.is_network_split = False + self.sync_all() + + def transact_and_mine(self, numblocks, mining_node): + min_fee = Decimal("0.00001") + # We will now mine numblocks blocks generating on average 100 transactions between each block + # We shuffle our confirmed txout set before each set of transactions + # small_txpuzzle_randfee will use the transactions that have inputs already in the chain when possible + # resorting to tx's that depend on the mempool when those run out + for i in range(numblocks): + random.shuffle(self.confutxo) + for j in range(random.randrange(100-50,100+50)): + from_index = random.randint(1,2) + (txhex, fee) = small_txpuzzle_randfee(self.nodes[from_index], self.confutxo, + self.memutxo, Decimal("0.005"), min_fee, min_fee) + tx_kbytes = (len(txhex) // 2) / 1000.0 + self.fees_per_kb.append(float(fee)/tx_kbytes) + sync_mempools(self.nodes[0:3],.1) + mined = mining_node.getblock(mining_node.generate(1)[0],True)["tx"] + sync_blocks(self.nodes[0:3],.1) + # update which txouts are confirmed + newmem = [] + for utx in self.memutxo: + if utx["txid"] in mined: + self.confutxo.append(utx) + else: + newmem.append(utx) + self.memutxo = newmem + + def run_test(self): + self.fees_per_kb = [] + self.memutxo = [] + self.confutxo = self.txouts # Start with the set of confirmed txouts after splitting + print("Will output estimates for 1/2/3/6/15/25 blocks") + + for i in range(2): + print("Creating transactions and mining them with a block size that can't keep up") + # Create transactions and mine 10 small blocks with node 2, but create txs faster than we can mine + self.transact_and_mine(10, self.nodes[2]) + check_estimates(self.nodes[1], self.fees_per_kb, 14) + + print("Creating transactions and mining them at a block size that is just big enough") + # Generate transactions while mining 10 more blocks, this time with node1 + # which mines blocks with capacity just above the rate that transactions are being created + self.transact_and_mine(10, self.nodes[1]) + check_estimates(self.nodes[1], self.fees_per_kb, 2) + + # Finish by mining a normal-sized block: + while len(self.nodes[1].getrawmempool()) > 0: + self.nodes[1].generate(1) + + sync_blocks(self.nodes[0:3],.1) + print("Final estimates after emptying mempools") + check_estimates(self.nodes[1], self.fees_per_kb, 2) + +if __name__ == '__main__': + EstimateFeeTest().main() diff --git a/qa/rpc-tests/test_framework/__init__.py b/qa/rpc-tests/test_framework/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/qa/rpc-tests/test_framework/authproxy.py b/qa/rpc-tests/test_framework/authproxy.py new file mode 100644 index 00000000..fa06d946 --- /dev/null +++ b/qa/rpc-tests/test_framework/authproxy.py @@ -0,0 +1,194 @@ + +""" +Copyright 2011 Jeff Garzik + +AuthServiceProxy has the following improvements over python-jsonrpc's +ServiceProxy class: + +- HTTP connections persist for the life of the AuthServiceProxy object +(if server supports HTTP/1.1) +- sends protocol 'version', per JSON-RPC 1.1 +- sends proper, incrementing 'id' +- sends Basic HTTP authentication headers +- parses all JSON numbers that look like floats as Decimal +- uses standard Python json lib + +Previous copyright, from python-jsonrpc/jsonrpc/proxy.py: + +Copyright (c) 2007 Jan-Klaas Kollhof + +This file is part of jsonrpc. + +jsonrpc is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This software is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this software; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" +import pdb +try: + import http.client as httplib +except ImportError: + import httplib +import base64 +import decimal +import json +import logging +try: + import urllib.parse as urlparse +except ImportError: + import urlparse + +USER_AGENT = "AuthServiceProxy/0.1" + +HTTP_TIMEOUT = 30 + +log = logging.getLogger("BitcoinRPC") + +class JSONRPCException(Exception): + def __init__(self, rpc_error): + Exception.__init__(self) + self.error = rpc_error + def __str__(self): + return "%d: %s" % (self.error["code"],self.error["message"]) + + +def EncodeDecimal(o): + if isinstance(o, decimal.Decimal): + return str(o) + raise TypeError(repr(o) + " is not JSON serializable") + +class AuthServiceProxy(object): + __id_count = 0 + + # ensure_ascii: escape unicode as \uXXXX, passed to json.dumps + def __init__(self, service_url, service_name=None, timeout=HTTP_TIMEOUT, connection=None, ensure_ascii=True): + self.__timeout = timeout + self.__service_url = service_url + self._service_name = service_name + self.ensure_ascii = ensure_ascii # can be toggled on the fly by tests + self.__url = urlparse.urlparse(service_url) + if self.__url.port is None: + port = 80 + else: + port = self.__url.port + (user, passwd) = (self.__url.username, self.__url.password) + try: + user = user.encode('utf8') + except AttributeError: + pass + try: + passwd = passwd.encode('utf8') + except AttributeError: + pass + authpair = user + b':' + passwd + self.__auth_header = b'Basic ' + base64.b64encode(authpair) + + if connection: + # Callables re-use the connection of the original proxy + self.__conn = connection + elif self.__url.scheme == 'https': + self.__conn = httplib.HTTPSConnection(self.__url.hostname, port, + timeout=timeout) + else: + self.__conn = httplib.HTTPConnection(self.__url.hostname, port, + timeout=timeout) + def reconnect(self): + if self.__url.port is None: + port = 80 + else: + port = self.__url.port + + if self.__url.scheme == 'https': + self.__conn = httplib.HTTPSConnection(self.__url.hostname, port, + timeout=self.__timeout) + else: + self.__conn = httplib.HTTPConnection(self.__url.hostname, port, + timeout=self.__timeout) + + def __getattr__(self, name): + if name.startswith('__') and name.endswith('__'): + # Python internal stuff + raise AttributeError + if self._service_name is not None: + name = "%s.%s" % (self._service_name, name) + return AuthServiceProxy(self.__service_url, name, connection=self.__conn) + + def _request(self, method, path, postdata): + ''' + Do a HTTP request, with retry if we get disconnected (e.g. due to a timeout). + This is a workaround for https://bugs.python.org/issue3566 which is fixed in Python 3.5. + ''' + headers = {'Host': self.__url.hostname, + 'User-Agent': USER_AGENT, + 'Authorization': self.__auth_header, + 'Content-type': 'application/json'} + while 1: + try: + self.__conn.request(method, path, postdata, headers) + return self._get_response() + except httplib.CannotSendRequest as e: + print("Cannot send request:", str(e)) + self.reconnect() + except httplib.BadStatusLine as e: + if e.line == "''": # if connection was closed, try again + self.__conn.close() + self.__conn.request(method, path, postdata, headers) + return self._get_response() + else: + raise + except (BrokenPipeError, ConnectionResetError): + # Python 3.5+ raises this instead of BadStatusLine when the connection was reset + self.__conn.close() + self.__conn.request(method, path, postdata, headers) + return self._get_response() + + def __call__(self, *args): + AuthServiceProxy.__id_count += 1 + + log.debug("-%s-> %s %s"%(AuthServiceProxy.__id_count, self._service_name, + json.dumps(args, default=EncodeDecimal, ensure_ascii=self.ensure_ascii))) + postdata = json.dumps({'version': '1.1', + 'method': self._service_name, + 'params': args, + 'id': AuthServiceProxy.__id_count}, default=EncodeDecimal, ensure_ascii=self.ensure_ascii) + response = self._request('POST', self.__url.path, postdata.encode('utf-8')) + if response['error'] is not None: + raise JSONRPCException(response['error']) + elif 'result' not in response: + raise JSONRPCException({ + 'code': -343, 'message': 'missing JSON-RPC result'}) + else: + return response['result'] + + def _batch(self, rpc_call_list): + postdata = json.dumps(list(rpc_call_list), default=EncodeDecimal, ensure_ascii=self.ensure_ascii) + log.debug("--> "+postdata) + return self._request('POST', self.__url.path, postdata.encode('utf-8')) + + def _get_response(self): + http_response = self.__conn.getresponse() + if http_response is None: + raise JSONRPCException({ + 'code': -342, 'message': 'missing HTTP response from server'}) + + content_type = http_response.getheader('Content-Type') + if content_type != 'application/json': + raise JSONRPCException({ + 'code': -342, 'message': 'non-JSON HTTP response with \'%i %s\' from server' % (http_response.status, http_response.reason)}) + + responsedata = http_response.read().decode('utf8') + response = json.loads(responsedata, parse_float=decimal.Decimal) + if "error" in response and response["error"] is None: + log.debug("<-%s- %s"%(response["id"], json.dumps(response["result"], default=EncodeDecimal, ensure_ascii=self.ensure_ascii))) + else: + log.debug("<-- "+responsedata) + return response diff --git a/qa/rpc-tests/test_framework/bignum.py b/qa/rpc-tests/test_framework/bignum.py new file mode 100644 index 00000000..ef800e4d --- /dev/null +++ b/qa/rpc-tests/test_framework/bignum.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# +# bignum.py +# +# This file is copied from python-bitcoinlib. +# +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +"""Bignum routines""" + + +import struct + + +# generic big endian MPI format + +def bn_bytes(v, have_ext=False): + ext = 0 + if have_ext: + ext = 1 + return ((v.bit_length()+7)//8) + ext + +def bn2bin(v): + s = bytearray() + i = bn_bytes(v) + while i > 0: + s.append((v >> ((i-1) * 8)) & 0xff) + i -= 1 + return s + +def bin2bn(s): + l = 0 + for ch in s: + l = (l << 8) | ch + return l + +def bn2mpi(v): + have_ext = False + if v.bit_length() > 0: + have_ext = (v.bit_length() & 0x07) == 0 + + neg = False + if v < 0: + neg = True + v = -v + + s = struct.pack(b">I", bn_bytes(v, have_ext)) + ext = bytearray() + if have_ext: + ext.append(0) + v_bin = bn2bin(v) + if neg: + if have_ext: + ext[0] |= 0x80 + else: + v_bin[0] |= 0x80 + return s + ext + v_bin + +def mpi2bn(s): + if len(s) < 4: + return None + s_size = bytes(s[:4]) + v_len = struct.unpack(b">I", s_size)[0] + if len(s) != (v_len + 4): + return None + if v_len == 0: + return 0 + + v_str = bytearray(s[4:]) + neg = False + i = v_str[0] + if i & 0x80: + neg = True + i &= ~0x80 + v_str[0] = i + + v = bin2bn(v_str) + + if neg: + return -v + return v + +# bitcoin-specific little endian format, with implicit size +def mpi2vch(s): + r = s[4:] # strip size + r = r[::-1] # reverse string, converting BE->LE + return r + +def bn2vch(v): + return bytes(mpi2vch(bn2mpi(v))) + +def vch2mpi(s): + r = struct.pack(b">I", len(s)) # size + r += s[::-1] # reverse string, converting LE->BE + return r + +def vch2bn(s): + return mpi2bn(vch2mpi(s)) + diff --git a/qa/rpc-tests/test_framework/blockstore.py b/qa/rpc-tests/test_framework/blockstore.py new file mode 100644 index 00000000..4bc27903 --- /dev/null +++ b/qa/rpc-tests/test_framework/blockstore.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +# BlockStore: a helper class that keeps a map of blocks and implements +# helper functions for responding to getheaders and getdata, +# and for constructing a getheaders message +# + +from .mininode import * +from io import BytesIO +import dbm.ndbm + +class BlockStore(object): + def __init__(self, datadir): + self.blockDB = dbm.ndbm.open(datadir + "/blocks", 'c') + self.currentBlock = 0 + self.headers_map = dict() + + def close(self): + self.blockDB.close() + + def get(self, blockhash): + serialized_block = None + try: + serialized_block = self.blockDB[repr(blockhash)] + except KeyError: + return None + f = BytesIO(serialized_block) + ret = CBlock() + ret.deserialize(f) + ret.calc_sha256() + return ret + + def get_header(self, blockhash): + try: + return self.headers_map[blockhash] + except KeyError: + return None + + # Note: this pulls full blocks out of the database just to retrieve + # the headers -- perhaps we could keep a separate data structure + # to avoid this overhead. + def headers_for(self, locator, hash_stop, current_tip=None): + if current_tip is None: + current_tip = self.currentBlock + current_block_header = self.get_header(current_tip) + if current_block_header is None: + return None + + response = msg_headers() + headersList = [ current_block_header ] + maxheaders = 2000 + while (headersList[0].sha256 not in locator.vHave): + prevBlockHash = headersList[0].hashPrevBlock + prevBlockHeader = self.get_header(prevBlockHash) + if prevBlockHeader is not None: + headersList.insert(0, prevBlockHeader) + else: + break + headersList = headersList[:maxheaders] # truncate if we have too many + hashList = [x.sha256 for x in headersList] + index = len(headersList) + if (hash_stop in hashList): + index = hashList.index(hash_stop)+1 + response.headers = headersList[:index] + return response + + def add_block(self, block): + block.calc_sha256() + try: + self.blockDB[repr(block.sha256)] = bytes(block.serialize()) + except TypeError as e: + print("Unexpected error: ", sys.exc_info()[0], e.args) + self.currentBlock = block.sha256 + self.headers_map[block.sha256] = CBlockHeader(block) + + def add_header(self, header): + self.headers_map[header.sha256] = header + + def get_blocks(self, inv): + responses = [] + for i in inv: + if (i.type == 2): # MSG_BLOCK + block = self.get(i.hash) + if block is not None: + responses.append(msg_block(block)) + return responses + + def get_locator(self, current_tip=None): + if current_tip is None: + current_tip = self.currentBlock + r = [] + counter = 0 + step = 1 + lastBlock = self.get(current_tip) + while lastBlock is not None: + r.append(lastBlock.hashPrevBlock) + for i in range(step): + lastBlock = self.get(lastBlock.hashPrevBlock) + if lastBlock is None: + break + counter += 1 + if counter > 10: + step *= 2 + locator = CBlockLocator() + locator.vHave = r + return locator + +class TxStore(object): + def __init__(self, datadir): + self.txDB = dbm.ndbm.open(datadir + "/transactions", 'c') + + def close(self): + self.txDB.close() + + def get(self, txhash): + serialized_tx = None + try: + serialized_tx = self.txDB[repr(txhash)] + except KeyError: + return None + f = BytesIO(serialized_tx) + ret = CTransaction() + ret.deserialize(f) + ret.calc_sha256() + return ret + + def add_transaction(self, tx): + tx.calc_sha256() + try: + self.txDB[repr(tx.sha256)] = bytes(tx.serialize()) + except TypeError as e: + print("Unexpected error: ", sys.exc_info()[0], e.args) + + def get_transactions(self, inv): + responses = [] + for i in inv: + if (i.type == 1): # MSG_TX + tx = self.get(i.hash) + if tx is not None: + responses.append(msg_tx(tx)) + return responses diff --git a/qa/rpc-tests/test_framework/blocktools.py b/qa/rpc-tests/test_framework/blocktools.py new file mode 100644 index 00000000..0d342720 --- /dev/null +++ b/qa/rpc-tests/test_framework/blocktools.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +# blocktools.py - utilities for manipulating blocks and transactions +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +import pdb +import binascii + +from .mininode import * +from .script import CScript, OP_TRUE, OP_CHECKSIG, OP_DROP, OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG +from .util import BTC + +# Create a block (with regtest difficulty) +def create_block(hashprev, coinbase, nTime=None, txns=None): + block = CBlock() + if nTime is None: + import time + block.nTime = int(time.time()+600) + else: + block.nTime = nTime + block.hashPrevBlock = hashprev + block.nBits = 0x207fffff # Will break after a difficulty adjustment... + if coinbase: + block.vtx.append(coinbase) + if txns: + block.vtx += txns + block.hashMerkleRoot = block.calc_merkle_root() + block.calc_sha256() + return block + +def serialize_script_num(value): + r = bytearray(0) + if value == 0: + return r + neg = value < 0 + absvalue = -value if neg else value + while (absvalue): + r.append(int(absvalue & 0xff)) + absvalue >>= 8 + if r[-1] & 0x80: + r.append(0x80 if neg else 0) + elif neg: + r[-1] |= 0x80 + return r + +# Create a coinbase transaction, assuming no miner fees. +# If pubkey is passed in, the coinbase output will be a P2PK output; +# otherwise an anyone-can-spend output. +def create_coinbase(height, pubkey = None): + coinbase = CTransaction() + coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff), + ser_string(serialize_script_num(height)), 0xffffffff)) + coinbaseoutput = CTxOut() + coinbaseoutput.nValue = 50 * COIN + halvings = int(height/150) # regtest + coinbaseoutput.nValue >>= halvings + if (pubkey != None): + coinbaseoutput.scriptPubKey = CScript([pubkey, OP_CHECKSIG]) + else: + coinbaseoutput.scriptPubKey = CScript([OP_TRUE]) + coinbase.vout = [ coinbaseoutput ] + coinbase.calc_sha256() + return coinbase + +# Create a transaction with an anyone-can-spend output, that spends the +# nth output of prevtx. pass a single integer value to make one output, +# or a list to create multiple outputs +def create_transaction(prevtx, n, sig, value): + if not type(value) is list: + value = [value] + tx = CTransaction() + assert(n < len(prevtx.vout)) + tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), sig, 0xffffffff)) + for v in value: + tx.vout.append(CTxOut(v, b"")) + tx.calc_sha256() + return tx + + +def bitcoinAddress2bin(btcAddress): + """convert a bitcoin address to binary data capable of being put in a CScript""" + # chop the version and checksum out of the bytes of the address + return decodeBase58(btcAddress)[1:-4] + + +B58_DIGITS = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' + + +def decodeBase58(s): + """Decode a base58-encoding string, returning bytes""" + if not s: + return b'' + + # Convert the string to an integer + n = 0 + for c in s: + n *= 58 + if c not in B58_DIGITS: + raise InvalidBase58Error('Character %r is not a valid base58 character' % c) + digit = B58_DIGITS.index(c) + n += digit + + # Convert the integer to bytes + h = '%x' % n + if len(h) % 2: + h = '0' + h + res = binascii.unhexlify(h.encode('utf8')) + + # Add padding back. + pad = 0 + for c in s[:-1]: + if c == B58_DIGITS[0]: + pad += 1 + else: + break + return b'\x00' * pad + res + +def createWastefulOutput(btcAddress): + """ Warning: Creates outputs that can't be spent by bitcoind""" + data = b"""this is junk data. this is junk data. this is junk data. this is junk data. this is junk data. +this is junk data. this is junk data. this is junk data. this is junk data. this is junk data. +this is junk data. this is junk data. this is junk data. this is junk data. this is junk data.""" + ret = CScript([data, OP_DROP, OP_DUP, OP_HASH160, bitcoinAddress2bin(btcAddress), OP_EQUALVERIFY, OP_CHECKSIG]) + return ret + + +def p2pkh(btcAddress): + """ create a pay-to-public-key-hash script""" + ret = CScript([OP_DUP, OP_HASH160, bitcoinAddress2bin(btcAddress), OP_EQUALVERIFY, OP_CHECKSIG]) + return ret + + +def createrawtransaction(inputs, outputs, outScriptGenerator=p2pkh): + """ + Create a transaction with the exact input and output syntax as the bitcoin-cli "createrawtransaction" command. + If you use the default outScriptGenerator, this function will return a hex string that exactly matches the + output of bitcoin-cli createrawtransaction. + """ + if not type(inputs) is list: + inputs = [inputs] + + tx = CTransaction() + for i in inputs: + tx.vin.append(CTxIn(COutPoint(i["txid"], i["vout"]), b"", 0xffffffff)) + for addr, amount in outputs.items(): + if addr == "data": + tx.vout.append(CTxOut(0, CScript([OP_RETURN, unhexlify(amount)]))) + else: + tx.vout.append(CTxOut(amount * BTC, outScriptGenerator(addr))) + tx.rehash() + return hexlify(tx.serialize()).decode("utf-8") diff --git a/qa/rpc-tests/test_framework/bumessages.py b/qa/rpc-tests/test_framework/bumessages.py new file mode 100644 index 00000000..2396abca --- /dev/null +++ b/qa/rpc-tests/test_framework/bumessages.py @@ -0,0 +1,415 @@ +from .nodemessages import * + + +class msg_buversion(object): + command = b"buversion" + + def __init__(self, addrFromPort=None): + self.addrFromPort = addrFromPort + pass + + def deserialize(self, f): + self.addrFromPort = struct.unpack("= 209: + conn.send_message(msg_verack()) + conn.ver_send = min(MY_VERSION, message.nVersion) + if message.nVersion < 209: + conn.ver_recv = conn.ver_send + self.remoteVersion = message.nVersion + + def on_verack(self, conn, message): + conn.ver_recv = conn.ver_send + self.verack_received = True + if self.remoteVersion >= EXPEDITED_VERSION: + msg = msg_buversion(conn.socket.getsockname()[1]) + self.connection.send_message(msg) + + def on_buverack(self, conn, message): + self.show_debug_msg("BU version ACK\n") + self.buverack_received = True + + def add_connection(self, conn): + self.connection = conn + + def add_parent(self, p): + self.parent = p + + # Request data for a list of block hashes + def get_data(self, block_hashes): + msg = msg_getdata() + for x in block_hashes: + msg.inv.append(CInv(2, x)) + self.connection.send_message(msg) + + def get_headers(self, locator, hashstop): + msg = msg_getheaders() + msg.locator.vHave = locator + msg.hashstop = hashstop + self.connection.send_message(msg) + + def send_block_inv(self, blockhash): + msg = msg_inv() + msg.inv = [CInv(2, blockhash)] + self.connection.send_message(msg) + + # Wrapper for the NodeConn's send_message function + def send_message(self, message): + self.connection.send_message(message) + + def on_inv(self, conn, message): + self.last_inv.append(message) + self.block_announced = True + for inv in message.inv: + if inv.type == CInv.MSG_BLOCK: + if self.requestOnInv & REQ_BLOCK: + msg = msg_getdata(inv) + self.send_message(msg) + self.show_debug_msg("requested block") + if self.requestOnInv & REQ_THINBLOCK: + msg = msg_getdata(CInv(CInv.MSG_THINBLOCK, inv.hash)) + self.send_message(msg) + self.show_debug_msg("requested thinblock") + if self.requestOnInv & REQ_XTHINBLOCK: + msg = msg_getdata(CInv(CInv.MSG_XTHINBLOCK, inv.hash)) + self.send_message(msg) + self.show_debug_msg("requested xtinblock") + + def on_headers(self, conn, message): + self.last_headers = message + self.block_announced = True + + def on_block(self, conn, message): + self.last_block = message.block + self.last_block.calc_sha256() + if self.parent and hasattr(self.parent, "on_block"): + self.parent.on_block(self, message) + + def on_thinblock(self, conn, message): + self.last_block = message.block + self.last_block.calc_sha256() + if self.parent and hasattr(self.parent, "on_thinblock"): + self.parent.on_thinblock(self, message) + + def on_xthinblock(self, conn, message): + self.last_block = message.block + self.last_block.calc_sha256() + if self.parent and hasattr(self.parent, "on_xthinblock"): + self.parent.on_xthinblock(self, message) + + def on_getdata(self, conn, message): + self.last_getdata.append(message) + + def on_pong(self, conn, message): + self.last_pong = message + if self.parent and hasattr(self.parent, "on_pong"): + self.parent.on_pong(self,message) + + def on_getheaders(self, conn, message): + self.last_getheaders = message + + def on_close(self, conn): + self.disconnected = True + if self.parent and hasattr(self.parent, "on_close"): + self.parent.on_close(self) + + # Test whether the last announcement we received had the + # right header or the right inv + # inv and headers should be lists of block hashes + def check_last_announcement(self, headers=None, inv=[]): + expect_headers = headers if headers != None else [] + expect_inv = inv if inv != [] else [] + + def test_function(): return self.block_announced + self.sync(test_function) + timeout = 5 + while timeout > 0: + with mininode_lock: + self.block_announced = False + + success = True + compare_inv = [] + if self.last_inv != []: + all_inv = [x.inv for x in self.last_inv] + for x in all_inv: + test_inv = [y.hash for y in x] + compare_inv = compare_inv + test_inv + + # Check whether the inventory received is within the list of block hashes that were + # mined (During a large reorg the inv's will be fewer than the actual hashes mined). + s = set(compare_inv) + expect_inv = [x for x in expect_inv if x in s] + if compare_inv != expect_inv: + success = False + + hash_headers = [] + if self.last_headers != None: + # treat headers as a list of block hashes + hash_headers = [x.sha256 for x in self.last_headers.headers] + if hash_headers != expect_headers: + success = False + + self.last_inv = [] + self.last_headers = None + + if success == True: + return success + + time.sleep(self.sleep_time) + timeout -= self.sleep_time + + # Syncing helpers + def sync(self, test_function, timeout=60): + while timeout > 0: + with mininode_lock: + if test_function(): + return + + time.sleep(self.sleep_time) + timeout -= self.sleep_time + raise AssertionError("Sync failed to complete") + + # The request manager does not deal with vectors of GETDATA requests but rather one GETDATA per + # hash, therefore we need to be able to sync_getdata one message at a time rather than in batches. + def sync_getdata(self, hash_list, timeout=60): + while timeout > 0: + with mininode_lock: + # Check whether any getdata responses are in the hash list and + # if so remove them from both lists. + for x in self.last_getdata: + for y in hash_list: + if (str(x.inv).find(hex(y)[2:]) > 0): + self.last_getdata.remove(x) + hash_list.remove(y) + if hash_list == []: + return + + time.sleep(self.sleep_time) + timeout -= self.sleep_time + raise AssertionError("Sync getdata failed to complete") + + def sync_with_ping(self, timeout=60): + self.send_message(msg_ping(nonce=self.ping_counter)) + + def test_function(): return self.last_pong.nonce == self.ping_counter + self.sync(test_function, timeout) + self.ping_counter += 1 + return + + def wait_for_block(self, blockhash, timeout=60): + def test_function(): return self.last_block != None and self.last_block.sha256 == blockhash + self.sync(test_function, timeout) + return + + def wait_for_getheaders(self, timeout=60): + def test_function(): return self.last_getheaders != None + self.sync(test_function, timeout) + return + + def wait_for_getdata(self, hash_list, timeout=60): + if hash_list == []: + return + + self.sync_getdata(hash_list, timeout) + return + + def wait_for_disconnect(self, timeout=60): + def test_function(): return self.disconnected + self.sync(test_function, timeout) + return + + def send_header_for_blocks(self, new_blocks): + headers_message = msg_headers() + headers_message.headers = [CBlockHeader(b) for b in new_blocks] + self.send_message(headers_message) + + def send_getblocks(self, locator): + getblocks_message = msg_getblocks() + getblocks_message.locator.vHave = locator + self.send_message(getblocks_message) + +class BasicBUCashNode(): + def __init__(self): + self.cnxns = {} + self.nblocks = 0 + self.nthin = 0 + self.nxthin = 0 + + def connect(self, id, ip, port, rpc=None, protohandler=None): + if not protohandler: + protohandler = BUProtocolHandler() + conn = NodeConn(ip, port, rpc, protohandler, bitcoinCash=True) + protohandler.add_connection(conn) + protohandler.add_parent(self) + self.cnxns[id] = protohandler + + def on_block(self, frm, message): + print("got block") + self.nblocks += 1 + + def on_thinblock(self, frm, message): + print("got thinblock") + self.nthin += 1 + + def on_xthinblock(self, frm, message): + print("got xthinblock") + self.nxthin += 1 + +class BasicBUNode: + def __init__(self): + self.cnxns = {} + self.nblocks = 0 + self.nthin = 0 + self.nxthin = 0 + + def connect(self, id, ip, port, rpc=None, protohandler=None): + if not protohandler: + protohandler = BUProtocolHandler() + conn = NodeConn(ip, port, rpc, protohandler, bitcoinCash = False) + protohandler.add_connection(conn) + protohandler.add_parent(self) + self.cnxns[id] = protohandler + + def on_block(self, frm, message): + print("got block") + self.nblocks += 1 + + def on_thinblock(self, frm, message): + print("got thinblock") + self.nthin += 1 + + def on_xthinblock(self, frm, message): + print("got xthinblock") + self.nxthin += 1 diff --git a/qa/rpc-tests/test_framework/comptool.py b/qa/rpc-tests/test_framework/comptool.py new file mode 100644 index 00000000..0913c4d6 --- /dev/null +++ b/qa/rpc-tests/test_framework/comptool.py @@ -0,0 +1,422 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +from .mininode import * +from .blockstore import BlockStore, TxStore +from .util import p2p_port +import time +''' +This is a tool for comparing two or more bitcoinds to each other +using a script provided. + +To use, create a class that implements get_tests(), and pass it in +as the test generator to TestManager. get_tests() should be a python +generator that returns TestInstance objects. See below for definition. +''' + +# TestNode behaves as follows: +# Configure with a BlockStore and TxStore +# on_inv: log the message but don't request +# on_headers: log the chain tip +# on_pong: update ping response map (for synchronization) +# on_getheaders: provide headers via BlockStore +# on_getdata: provide blocks via BlockStore + +global mininode_lock + +class RejectResult(object): + ''' + Outcome that expects rejection of a transaction or block. + ''' + def __init__(self, code, reason=b''): + self.code = code + self.reason = reason + def match(self, other): + if self.code != other.code: + return False + return other.reason.startswith(self.reason) + def __repr__(self): + return '%i:%s' % (self.code,self.reason or '*') + +class TestNode(NodeConnCB): + + def __init__(self, block_store, tx_store): + NodeConnCB.__init__(self) + self.conn = None + self.bestblockhash = None + self.block_store = block_store + self.block_request_map = {} + self.tx_store = tx_store + self.tx_request_map = {} + self.block_reject_map = {} + self.tx_reject_map = {} + + # When the pingmap is non-empty we're waiting for + # a response + self.pingMap = {} + self.lastInv = [] + self.closed = False + + def on_close(self, conn): + self.closed = True + + def add_connection(self, conn): + self.conn = conn + + def on_headers(self, conn, message): + if len(message.headers) > 0: + best_header = message.headers[-1] + best_header.calc_sha256() + self.bestblockhash = best_header.sha256 + + def on_getheaders(self, conn, message): + response = self.block_store.headers_for(message.locator, message.hashstop) + if response is not None: + conn.send_message(response) + + def on_getdata(self, conn, message): + [conn.send_message(r) for r in self.block_store.get_blocks(message.inv)] + [conn.send_message(r) for r in self.tx_store.get_transactions(message.inv)] + + for i in message.inv: + if i.type == 1: + self.tx_request_map[i.hash] = True + elif i.type == 2: + self.block_request_map[i.hash] = True + + def on_inv(self, conn, message): + self.lastInv = [x.hash for x in message.inv] + + def on_pong(self, conn, message): + try: + del self.pingMap[message.nonce] + except KeyError: + raise AssertionError("Got pong for unknown ping [%s]" % repr(message)) + + def on_reject(self, conn, message): + if message.message == b'tx': + self.tx_reject_map[message.data] = RejectResult(message.code, message.reason) + if message.message == b'block': + self.block_reject_map[message.data] = RejectResult(message.code, message.reason) + + def send_inv(self, obj): + mtype = 2 if isinstance(obj, CBlock) else 1 + self.conn.send_message(msg_inv([CInv(mtype, obj.sha256)])) + + def send_getheaders(self): + # We ask for headers from their last tip. + m = msg_getheaders() + m.locator = self.block_store.get_locator(self.bestblockhash) + self.conn.send_message(m) + + # This assumes BIP31 + def send_ping(self, nonce): + self.pingMap[nonce] = True + self.conn.send_message(msg_ping(nonce)) + + def received_ping_response(self, nonce): + return nonce not in self.pingMap + + def send_mempool(self): + self.lastInv = [] + self.conn.send_message(msg_mempool()) + +# TestInstance: +# +# Instances of these are generated by the test generator, and fed into the +# comptool. +# +# "blocks_and_transactions" should be an array of +# [obj, True/False/None, hash/None]: +# - obj is either a CBlock, CBlockHeader, or a CTransaction, and +# - the second value indicates whether the object should be accepted +# into the blockchain or mempool (for tests where we expect a certain +# answer), or "None" if we don't expect a certain answer and are just +# comparing the behavior of the nodes being tested. +# - the third value is the hash to test the tip against (if None or omitted, +# use the hash of the block) +# - NOTE: if a block header, no test is performed; instead the header is +# just added to the block_store. This is to facilitate block delivery +# when communicating with headers-first clients (when withholding an +# intermediate block). +# sync_every_block: if True, then each block will be inv'ed, synced, and +# nodes will be tested based on the outcome for the block. If False, +# then inv's accumulate until all blocks are processed (or max inv size +# is reached) and then sent out in one inv message. Then the final block +# will be synced across all connections, and the outcome of the final +# block will be tested. +# sync_every_tx: analogous to behavior for sync_every_block, except if outcome +# on the final tx is None, then contents of entire mempool are compared +# across all connections. (If outcome of final tx is specified as true +# or false, then only the last tx is tested against outcome.) + +class TestInstance(object): + def __init__(self, objects=None, sync_every_block=True, sync_every_tx=False): + self.blocks_and_transactions = objects if objects else [] + self.sync_every_block = sync_every_block + self.sync_every_tx = sync_every_tx + +class TestManager(object): + + def __init__(self, testgen, datadir): + self.test_generator = testgen + self.connections = [] + self.test_nodes = [] + self.block_store = BlockStore(datadir) + self.tx_store = TxStore(datadir) + self.ping_counter = 1 + + def add_all_connections(self, nodes): + for i in range(len(nodes)): + # Create a p2p connection to each node + test_node = TestNode(self.block_store, self.tx_store) + self.test_nodes.append(test_node) + self.connections.append(NodeConn('127.0.0.1', p2p_port(i), nodes[i], test_node)) + # Make sure the TestNode (callback class) has a reference to its + # associated NodeConn + test_node.add_connection(self.connections[-1]) + + def clear_all_connections(self): + self.connections = [] + self.test_nodes = [] + + def wait_for_disconnections(self): + def disconnected(): + return all(node.closed for node in self.test_nodes) + return wait_until(disconnected, timeout=10) + + def wait_for_verack(self): + def veracked(): + return all(node.verack_received for node in self.test_nodes) + return wait_until(veracked, timeout=10) + + def wait_for_pings(self, counter): + def received_pongs(): + return all(node.received_ping_response(counter) for node in self.test_nodes) + return wait_until(received_pongs) + + # sync_blocks: Wait for all connections to request the blockhash given + # then send get_headers to find out the tip of each node, and synchronize + # the response by using a ping (and waiting for pong with same nonce). + def sync_blocks(self, blockhash, num_blocks): + def blocks_requested(): + return all( + blockhash in node.block_request_map and node.block_request_map[blockhash] + for node in self.test_nodes + ) + # --> error if not requested + if not wait_until(blocks_requested, attempts=20*num_blocks): + # print [ c.cb.block_request_map for c in self.connections ] + raise AssertionError("Not all nodes requested block") + + # Send getheaders message + [ c.cb.send_getheaders() for c in self.connections ] + + # Send ping and wait for response -- synchronization hack + [ c.cb.send_ping(self.ping_counter) for c in self.connections ] + self.wait_for_pings(self.ping_counter) + self.ping_counter += 1 + + # Analogous to sync_block (see above) + def sync_transaction(self, txhash, num_events): + # Wait for nodes to request transaction (50ms sleep * 20 tries * num_events) + def transaction_requested(): + return all( + txhash in node.tx_request_map and node.tx_request_map[txhash] + for node in self.test_nodes + ) + + # --> error if not requested + if not wait_until(transaction_requested, attempts=20*num_events): + # print [ c.cb.tx_request_map for c in self.connections ] + raise AssertionError("Not all nodes requested transaction") + + # Get the mempool + [ c.cb.send_mempool() for c in self.connections ] + + # Send ping and wait for response -- synchronization hack + [ c.cb.send_ping(self.ping_counter) for c in self.connections ] + self.wait_for_pings(self.ping_counter) + self.ping_counter += 1 + + # Sort inv responses from each node + with mininode_lock: + [ c.cb.lastInv.sort() for c in self.connections ] + + # Verify that the tip of each connection all agree with each other, and + # with the expected outcome (if given) + def check_results(self, blockhash, outcome): + with mininode_lock: + + for c in self.connections: + if outcome is None: + if c.cb.bestblockhash != self.connections[0].cb.bestblockhash: + print("Node ", c.addr, " has best block ", hex(c.cb.bestblockhash), ". Expecting ", hex(self.connections[0].cb.bestblockhash)) + return False + elif isinstance(outcome, RejectResult): # Check that block was rejected w/ code + if c.cb.bestblockhash == blockhash: + return False + if blockhash not in c.cb.block_reject_map: + print('Block not in reject map: %064x' % (blockhash)) + return False + if not outcome.match(c.cb.block_reject_map[blockhash]): + print('Block rejected with %s instead of expected %s: %064x' % (c.cb.block_reject_map[blockhash], outcome, blockhash)) + return False + elif ((c.cb.bestblockhash == blockhash) != outcome): + print("Node ", c.addr, " has best block ", hex(c.cb.bestblockhash), ". Expecting ", hex(blockhash), outcome) + hsh = c.rpc.getbestblockhash() + print("Quick RPC returns", hsh) + t = 0 + # give 20 seconds to sync, this is a pretty generous number. How much time might it take + # an underpowered test node running 4-6 copies of bitcoind to sync them? + while t < 10 and hsh != hex(blockhash)[2:]: # hex(blockhash) returns "0x..." whereas hsh does not have the "0x" + t += 1 + time.sleep(2) + hsh = c.rpc.getbestblockhash() + if t == 10: + print("Delayed RPC returns", hsh) + + rpcblock = c.rpc.getbestblockhash() + block = hex(blockhash)[2:] + #sometimes a leading zero or two are missing from the blockhash. Replace these. + while (len(block) < 64): + block = '0' + block + if rpcblock == block: + return True + else: + return False + + return True + + # Either check that the mempools all agree with each other, or that + # txhash's presence in the mempool matches the outcome specified. + # This is somewhat of a strange comparison, in that we're either comparing + # a particular tx to an outcome, or the entire mempools altogether; + # perhaps it would be useful to add the ability to check explicitly that + # a particular tx's existence in the mempool is the same across all nodes. + def check_mempool(self, txhash, outcome): + with mininode_lock: + for c in self.connections: + if outcome is None: + # Make sure the mempools agree with each other + if c.cb.lastInv != self.connections[0].cb.lastInv: + # print c.rpc.getrawmempool() + return False + elif isinstance(outcome, RejectResult): # Check that tx was rejected w/ code + if txhash in c.cb.lastInv: + return False + if txhash not in c.cb.tx_reject_map: + print('Tx not in reject map: %064x' % (txhash)) + return False + if not outcome.match(c.cb.tx_reject_map[txhash]): + print('Tx rejected with %s instead of expected %s: %064x' % (c.cb.tx_reject_map[txhash], outcome, txhash)) + return False + elif ((txhash in c.cb.lastInv) != outcome): + # print c.rpc.getrawmempool(), c.cb.lastInv + return False + return True + + def run(self): + # Wait until verack is received + self.wait_for_verack() + + test_number = 1 + for test_instance in self.test_generator.get_tests(): + # We use these variables to keep track of the last block + # and last transaction in the tests, which are used + # if we're not syncing on every block or every tx. + [ block, block_outcome, tip ] = [ None, None, None ] + [ tx, tx_outcome ] = [ None, None ] + invqueue = [] + + for test_obj in test_instance.blocks_and_transactions: + b_or_t = test_obj[0] + outcome = test_obj[1] + # Determine if we're dealing with a block or tx + if isinstance(b_or_t, CBlock): # Block test runner + block = b_or_t + block_outcome = outcome + tip = block.sha256 + # each test_obj can have an optional third argument + # to specify the tip we should compare with + # (default is to use the block being tested) + if len(test_obj) >= 3: + tip = test_obj[2] + + # Add to shared block_store, set as current block + # If there was an open getdata request for the block + # previously, and we didn't have an entry in the + # block_store, then immediately deliver, because the + # node wouldn't send another getdata request while + # the earlier one is outstanding. + first_block_with_hash = True + if self.block_store.get(block.sha256) is not None: + first_block_with_hash = False + with mininode_lock: + self.block_store.add_block(block) + for c in self.connections: + if first_block_with_hash and block.sha256 in c.cb.block_request_map and c.cb.block_request_map[block.sha256] == True: + # There was a previous request for this block hash + # Most likely, we delivered a header for this block + # but never had the block to respond to the getdata + c.send_message(msg_block(block)) + else: + c.cb.block_request_map[block.sha256] = False + # Either send inv's to each node and sync, or add + # to invqueue for later inv'ing. + if (test_instance.sync_every_block): + [ c.cb.send_inv(block) for c in self.connections ] + self.sync_blocks(block.sha256, 1) + if (not self.check_results(tip, outcome)): + raise AssertionError("Test failed at test %d" % test_number) + else: + invqueue.append(CInv(2, block.sha256)) + elif isinstance(b_or_t, CBlockHeader): + block_header = b_or_t + self.block_store.add_header(block_header) + else: # Tx test runner + assert(isinstance(b_or_t, CTransaction)) + tx = b_or_t + tx_outcome = outcome + # Add to shared tx store and clear map entry + with mininode_lock: + self.tx_store.add_transaction(tx) + for c in self.connections: + c.cb.tx_request_map[tx.sha256] = False + # Again, either inv to all nodes or save for later + if (test_instance.sync_every_tx): + [ c.cb.send_inv(tx) for c in self.connections ] + self.sync_transaction(tx.sha256, 1) + if (not self.check_mempool(tx.sha256, outcome)): + raise AssertionError("Test failed at test %d" % test_number) + else: + invqueue.append(CInv(1, tx.sha256)) + # Ensure we're not overflowing the inv queue + if len(invqueue) == MAX_INV_SZ: + [ c.send_message(msg_inv(invqueue)) for c in self.connections ] + invqueue = [] + + # Do final sync if we weren't syncing on every block or every tx. + if (not test_instance.sync_every_block and block is not None): + if len(invqueue) > 0: + [ c.send_message(msg_inv(invqueue)) for c in self.connections ] + invqueue = [] + self.sync_blocks(block.sha256, len(test_instance.blocks_and_transactions)) + if (not self.check_results(tip, block_outcome)): + raise AssertionError("Block test failed at test %d" % test_number) + if (not test_instance.sync_every_tx and tx is not None): + if len(invqueue) > 0: + [ c.send_message(msg_inv(invqueue)) for c in self.connections ] + invqueue = [] + self.sync_transaction(tx.sha256, len(test_instance.blocks_and_transactions)) + if (not self.check_mempool(tx.sha256, tx_outcome)): + raise AssertionError("Mempool test failed at test %d" % test_number) + + print("Test %d: PASS" % test_number, [ c.rpc.getblockcount() for c in self.connections ]) + test_number += 1 + + [ c.disconnect_node() for c in self.connections ] + self.wait_for_disconnections() + self.block_store.close() + self.tx_store.close() diff --git a/qa/rpc-tests/test_framework/coverage.py b/qa/rpc-tests/test_framework/coverage.py new file mode 100644 index 00000000..fa538055 --- /dev/null +++ b/qa/rpc-tests/test_framework/coverage.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +""" +This module contains utilities for doing coverage analysis on the RPC +interface. + +It provides a way to track which RPC commands are exercised during +testing. + +""" +import os +import pdb + +REFERENCE_FILENAME = 'rpc_interface.txt' + + +class AuthServiceProxyWrapper(object): + """ + An object that wraps AuthServiceProxy to record specific RPC calls. + + """ + def __init__(self, auth_service_proxy_instance, coverage_logfile=None): + """ + Kwargs: + auth_service_proxy_instance (AuthServiceProxy): the instance + being wrapped. + coverage_logfile (str): if specified, write each service_name + out to a file when called. + + """ + self.auth_service_proxy_instance = auth_service_proxy_instance + self.coverage_logfile = coverage_logfile + + def __getattr__(self, *args, **kwargs): + return_val = self.auth_service_proxy_instance.__getattr__( + *args, **kwargs) + + return AuthServiceProxyWrapper(return_val, self.coverage_logfile) + + def __call__(self, *args, **kwargs): + """ + Delegates to AuthServiceProxy, then writes the particular RPC method + called to a file. + + """ + return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs) + rpc_method = self.auth_service_proxy_instance._service_name + + if self.coverage_logfile: + with open(self.coverage_logfile, 'a+') as f: + f.write("%s\n" % rpc_method) + + return return_val + + @property + def url(self): + return self.auth_service_proxy_instance.url + + +def get_filename(dirname, n_node): + """ + Get a filename unique to the test process ID and node. + + This file will contain a list of RPC commands covered. + """ + pid = str(os.getpid()) + return os.path.join( + dirname, "coverage.pid%s.node%s.txt" % (pid, str(n_node))) + + +def write_all_rpc_commands(dirname, node): + """ + Write out a list of all RPC functions available in `bitcoin-cli` for + coverage comparison. This will only happen once per coverage + directory. + + Args: + dirname (str): temporary test dir + node (AuthServiceProxy): client + + Returns: + bool. if the RPC interface file was written. + + """ + filename = os.path.join(dirname, REFERENCE_FILENAME) + + if os.path.isfile(filename): + return False + + help_output = node.help().split('\n') + commands = set() + + for line in help_output: + line = line.strip() + + # Ignore blanks and headers + if line and not line.startswith('='): + commands.add("%s\n" % line.split()[0]) + + with open(filename, 'w') as f: + f.writelines(list(commands)) + + return True diff --git a/qa/rpc-tests/test_framework/key.py b/qa/rpc-tests/test_framework/key.py new file mode 100644 index 00000000..ba3038fe --- /dev/null +++ b/qa/rpc-tests/test_framework/key.py @@ -0,0 +1,215 @@ +# Copyright (c) 2011 Sam Rushing +# +# key.py - OpenSSL wrapper +# +# This file is modified from python-bitcoinlib. +# + +"""ECC secp256k1 crypto routines + +WARNING: This module does not mlock() secrets; your private keys may end up on +disk in swap! Use with caution! +""" + +import ctypes +import ctypes.util +import hashlib +import sys + +ssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library ('ssl') or 'libeay32') + +ssl.BN_new.restype = ctypes.c_void_p +ssl.BN_new.argtypes = [] + +ssl.BN_bin2bn.restype = ctypes.c_void_p +ssl.BN_bin2bn.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.c_void_p] + +ssl.BN_CTX_free.restype = None +ssl.BN_CTX_free.argtypes = [ctypes.c_void_p] + +ssl.BN_CTX_new.restype = ctypes.c_void_p +ssl.BN_CTX_new.argtypes = [] + +ssl.ECDH_compute_key.restype = ctypes.c_int +ssl.ECDH_compute_key.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p] + +ssl.ECDSA_sign.restype = ctypes.c_int +ssl.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] + +ssl.ECDSA_verify.restype = ctypes.c_int +ssl.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p] + +ssl.EC_KEY_free.restype = None +ssl.EC_KEY_free.argtypes = [ctypes.c_void_p] + +ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p +ssl.EC_KEY_new_by_curve_name.argtypes = [ctypes.c_int] + +ssl.EC_KEY_get0_group.restype = ctypes.c_void_p +ssl.EC_KEY_get0_group.argtypes = [ctypes.c_void_p] + +ssl.EC_KEY_get0_public_key.restype = ctypes.c_void_p +ssl.EC_KEY_get0_public_key.argtypes = [ctypes.c_void_p] + +ssl.EC_KEY_set_private_key.restype = ctypes.c_int +ssl.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + +ssl.EC_KEY_set_conv_form.restype = None +ssl.EC_KEY_set_conv_form.argtypes = [ctypes.c_void_p, ctypes.c_int] + +ssl.EC_KEY_set_public_key.restype = ctypes.c_int +ssl.EC_KEY_set_public_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + +ssl.i2o_ECPublicKey.restype = ctypes.c_void_p +ssl.i2o_ECPublicKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + +ssl.EC_POINT_new.restype = ctypes.c_void_p +ssl.EC_POINT_new.argtypes = [ctypes.c_void_p] + +ssl.EC_POINT_free.restype = None +ssl.EC_POINT_free.argtypes = [ctypes.c_void_p] + +ssl.EC_POINT_mul.restype = ctypes.c_int +ssl.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] + +# this specifies the curve used with ECDSA. +NID_secp256k1 = 714 # from openssl/obj_mac.h + +# Thx to Sam Devlin for the ctypes magic 64-bit fix. +def _check_result(val, func, args): + if val == 0: + raise ValueError + else: + return ctypes.c_void_p (val) + +ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p +ssl.EC_KEY_new_by_curve_name.errcheck = _check_result + +class CECKey(object): + """Wrapper around OpenSSL's EC_KEY""" + + POINT_CONVERSION_COMPRESSED = 2 + POINT_CONVERSION_UNCOMPRESSED = 4 + + def __init__(self): + self.k = ssl.EC_KEY_new_by_curve_name(NID_secp256k1) + + def __del__(self): + if ssl: + ssl.EC_KEY_free(self.k) + self.k = None + + def set_secretbytes(self, secret): + priv_key = ssl.BN_bin2bn(secret, 32, ssl.BN_new()) + group = ssl.EC_KEY_get0_group(self.k) + pub_key = ssl.EC_POINT_new(group) + ctx = ssl.BN_CTX_new() + if not ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx): + raise ValueError("Could not derive public key from the supplied secret.") + ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx) + ssl.EC_KEY_set_private_key(self.k, priv_key) + ssl.EC_KEY_set_public_key(self.k, pub_key) + ssl.EC_POINT_free(pub_key) + ssl.BN_CTX_free(ctx) + return self.k + + def set_privkey(self, key): + self.mb = ctypes.create_string_buffer(key) + return ssl.d2i_ECPrivateKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key)) + + def set_pubkey(self, key): + self.mb = ctypes.create_string_buffer(key) + return ssl.o2i_ECPublicKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key)) + + def get_privkey(self): + size = ssl.i2d_ECPrivateKey(self.k, 0) + mb_pri = ctypes.create_string_buffer(size) + ssl.i2d_ECPrivateKey(self.k, ctypes.byref(ctypes.pointer(mb_pri))) + return mb_pri.raw + + def get_pubkey(self): + size = ssl.i2o_ECPublicKey(self.k, 0) + mb = ctypes.create_string_buffer(size) + ssl.i2o_ECPublicKey(self.k, ctypes.byref(ctypes.pointer(mb))) + return mb.raw + + def get_raw_ecdh_key(self, other_pubkey): + ecdh_keybuffer = ctypes.create_string_buffer(32) + r = ssl.ECDH_compute_key(ctypes.pointer(ecdh_keybuffer), 32, + ssl.EC_KEY_get0_public_key(other_pubkey.k), + self.k, 0) + if r != 32: + raise Exception('CKey.get_ecdh_key(): ECDH_compute_key() failed') + return ecdh_keybuffer.raw + + def get_ecdh_key(self, other_pubkey, kdf=lambda k: hashlib.sha256(k).digest()): + # FIXME: be warned it's not clear what the kdf should be as a default + r = self.get_raw_ecdh_key(other_pubkey) + return kdf(r) + + def sign(self, hash): + # FIXME: need unit tests for below cases + if not isinstance(hash, bytes): + raise TypeError('Hash must be bytes instance; got %r' % hash.__class__) + if len(hash) != 32: + raise ValueError('Hash must be exactly 32 bytes long') + + sig_size0 = ctypes.c_uint32() + sig_size0.value = ssl.ECDSA_size(self.k) + mb_sig = ctypes.create_string_buffer(sig_size0.value) + result = ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k) + assert 1 == result + return mb_sig.raw[:sig_size0.value] + + def verify(self, hash, sig): + """Verify a DER signature""" + return ssl.ECDSA_verify(0, hash, len(hash), sig, len(sig), self.k) == 1 + + def set_compressed(self, compressed): + if compressed: + form = self.POINT_CONVERSION_COMPRESSED + else: + form = self.POINT_CONVERSION_UNCOMPRESSED + ssl.EC_KEY_set_conv_form(self.k, form) + + +class CPubKey(bytes): + """An encapsulated public key + + Attributes: + + is_valid - Corresponds to CPubKey.IsValid() + is_fullyvalid - Corresponds to CPubKey.IsFullyValid() + is_compressed - Corresponds to CPubKey.IsCompressed() + """ + + def __new__(cls, buf, _cec_key=None): + self = super(CPubKey, cls).__new__(cls, buf) + if _cec_key is None: + _cec_key = CECKey() + self._cec_key = _cec_key + self.is_fullyvalid = _cec_key.set_pubkey(self) != 0 + return self + + @property + def is_valid(self): + return len(self) > 0 + + @property + def is_compressed(self): + return len(self) == 33 + + def verify(self, hash, sig): + return self._cec_key.verify(hash, sig) + + def __str__(self): + return repr(self) + + def __repr__(self): + # Always have represent as b'' so test cases don't have to + # change for py2/3 + if sys.version > '3': + return '%s(%s)' % (self.__class__.__name__, super(CPubKey, self).__repr__()) + else: + return '%s(b%s)' % (self.__class__.__name__, super(CPubKey, self).__repr__()) + diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py new file mode 100644 index 00000000..3111ebf0 --- /dev/null +++ b/qa/rpc-tests/test_framework/mininode.py @@ -0,0 +1,437 @@ +#!/usr/bin/env python3 +# Copyright (c) 2010 ArtForz -- public domain half-a-node +# Copyright (c) 2012 Jeff Garzik +# Copyright (c) 2010-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. + +# +# mininode.py - Bitcoin P2P network half-a-node +# +# This python code was modified from ArtForz' public domain half-a-node, as +# found in the mini-node branch of http://github.com/jgarzik/pynode. +# +# NodeConn: an object which manages p2p connectivity to a bitcoin node +# NodeConnCB: a base class that describes the interface for receiving +# callbacks with network messages from a NodeConn +# CBlock, CTransaction, CBlockHeader, CTxIn, CTxOut, etc....: +# data structures that should map to corresponding structures in +# bitcoin/primitives +# msg_block, msg_tx, msg_headers, etc.: +# data structures that represent network messages +# ser_*, deser_*: functions that handle serialization/deserialization + +import pdb +import struct +import socket +import asyncore +import time +import sys +import random +from binascii import hexlify, unhexlify +from io import BytesIO +from codecs import encode +import hashlib +from threading import RLock +from threading import Thread +import logging +import copy + +from .nodemessages import * +from .bumessages import * + +BIP0031_VERSION = 60000 + +MAX_INV_SZ = 50000 +MAX_BLOCK_SIZE = 1000000 + +class MiniNodeError(Exception): + pass + +class DisconnectedError(MiniNodeError): + pass + +# 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) +mininode_socket_map = dict() + +# This is what a callback should look like for NodeConn +# Reimplement the on_* functions to provide handling for events +class NodeConnCB(object): + def __init__(self): + self.verack_received = False + # deliver_sleep_time is helpful for debugging race conditions in p2p + # tests; it causes message delivery to sleep for the specified time + # before acquiring the global lock and delivering the next message. + self.deliver_sleep_time = None + self.disconnected = False + + def set_deliver_sleep_time(self, value): + with mininode_lock: + self.deliver_sleep_time = value + + def get_deliver_sleep_time(self): + with mininode_lock: + return self.deliver_sleep_time + + # Spin until verack message is received from the node. + # Tests may want to use this as a signal that the test can begin. + # This can be called from the testing thread, so it needs to acquire the + # global lock. + def wait_for_verack(self): + while True: + if self.disconnected: + raise DisconnectedError() + with mininode_lock: + if self.verack_received: + return + time.sleep(0.05) + + def deliver(self, conn, message): + deliver_sleep = self.get_deliver_sleep_time() + if deliver_sleep is not None: + time.sleep(deliver_sleep) + with mininode_lock: + fn = 'on_' + message.command.decode('ascii') + try: + getattr(self, fn)(conn, message) + except: + print("ERROR delivering %s (%s) to %s" % (repr(message), sys.exc_info()[0], fn)) + + def on_version(self, conn, message): + if message.nVersion >= 209: + conn.send_message(msg_verack()) + conn.ver_send = min(MY_VERSION, message.nVersion) + if message.nVersion < 209: + conn.ver_recv = conn.ver_send + + def on_verack(self, conn, message): + conn.ver_recv = conn.ver_send + self.verack_received = True + + def on_inv(self, conn, message): + want = msg_getdata() + for i in message.inv: + if i.type != 0: + want.inv.append(i) + if len(want.inv): + conn.send_message(want) + + def on_addr(self, conn, message): pass + + def on_alert(self, conn, message): pass + + def on_getdata(self, conn, message): pass + + def on_getblocks(self, conn, message): pass + + def on_tx(self, conn, message): pass + + def on_block(self, conn, message): pass + + def on_getaddr(self, conn, message): pass + + def on_headers(self, conn, message): pass + + def on_getheaders(self, conn, message): pass + + def on_ping(self, conn, message): + if conn.ver_send > BIP0031_VERSION: + conn.send_message(msg_pong(message.nonce)) + + def on_reject(self, conn, message): pass + + def on_close(self, conn): + self.disconnected=True + pass + + def on_mempool(self, conn): pass + + def on_pong(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 + + +def dupdate(x, y): + x.update(y) + return x + + +class MsgAnnotater: + def __init__(self): + self.idx = 0 + + def annotate(self, msg, conn): + msg.idx = self.idx + msg.offset = conn.curIndex + self.idx += 1 + return msg + +# The actual NodeConn class +# This class provides an interface for a p2p connection to a specified node + + +class NodeConn(asyncore.dispatcher): + messagemap = dupdate({ + b"version": msg_version, + b"verack": msg_verack, + b"addr": msg_addr, + b"alert": msg_alert, + b"inv": msg_inv, + b"getdata": msg_getdata, + b"getblocks": msg_getblocks, + b"tx": msg_tx, + b"block": msg_block, + b"getaddr": msg_getaddr, + b"ping": msg_ping, + b"pong": msg_pong, + b"headers": msg_headers, + b"getheaders": msg_getheaders, + b"reject": msg_reject, + b"mempool": msg_mempool, + b"sendheaders": msg_sendheaders, + }, bumessagemap) + + BTC_MAGIC_BYTES = { + "mainnet": b"\xf9\xbe\xb4\xd9", # mainnet + "testnet3": b"\x0b\x11\x09\x07", # testnet3 + "regtest": b"\xfa\xbf\xb5\xda" # regtest + } + + CASH_MAGIC_BYTES = { + "mainnet": b"\xe3\xe1\xf3\xe8", + "testnet3": b"\xf4\xe5\xf3\xf4", + "regtest": b"\xda\xb5\xbf\xfa", + } + + def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=1, bitcoinCash=False): + self.bitcoinCash = bitcoinCash + if self.bitcoinCash: + self.MAGIC_BYTES = self.CASH_MAGIC_BYTES + else: + self.MAGIC_BYTES = self.BTC_MAGIC_BYTES + asyncore.dispatcher.__init__(self, map=mininode_socket_map) + self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport)) + self.dstaddr = dstaddr + self.dstport = dstport + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.sendbuf = b"" + self.recvbuf = b"" + self.ver_send = 209 + self.ver_recv = 209 + self.last_sent = 0 + self.state = "connecting" + self.network = net + self.cb = callback + self.disconnect = False + self.curIndex = 0 + # stuff version msg into sendbuf + vt = msg_version() + vt.nServices = services + vt.addrTo.ip = self.dstaddr + vt.addrTo.port = self.dstport + vt.addrFrom.ip = "0.0.0.0" + vt.addrFrom.port = 0 + self.send_message(vt, True) + print('MiniNode: Connecting to Bitcoin Node IP # ' + dstaddr + ':' + + str(dstport)) + try: + self.connect((dstaddr, dstport)) + except: + self.handle_close() + self.rpc = rpc + + def show_debug_msg(self, msg): + self.log.debug(msg) + + def handle_connect(self): + self.show_debug_msg("MiniNode: Connected & Listening: \n") + self.state = "connected" + + def handle_close(self): + self.show_debug_msg("MiniNode: Closing Connection to %s:%d... " + % (self.dstaddr, self.dstport)) + self.state = "closed" + self.recvbuf = b"" + self.sendbuf = b"" + try: + self.close() + except: + pass + self.cb.on_close(self) + + def parse_messages(self, buffer): + if not type(buffer) == type(b""): # if not a buffer its a file + buffer = buffer.read() + tmp = self.cb + ret = [] + ann = MsgAnnotater() + self.cb = type("", (), {"deliver": lambda self, conn, msg: ret.append(ann.annotate(msg, conn))})() + self.inject_data(buffer) + self.cp = tmp + return ret + + def inject_data(self, buffer): + self.recvbuf += buffer + self.got_data() + + def handle_read(self): + try: + t = self.recv(8192) + if len(t) > 0: + self.recvbuf += t + self.got_data() + except: + pass + + def readable(self): + return True + + def writable(self): + with mininode_lock: + length = len(self.sendbuf) + return (length > 0) + + def handle_write(self): + with mininode_lock: + try: + sent = self.send(self.sendbuf) + except: + self.handle_close() + return + self.sendbuf = self.sendbuf[sent:] + + def got_data(self): + self.recvBufLen = len(self.recvbuf) + try: + while True: + nowLen = len(self.recvbuf) + self.curIndex += (self.recvBufLen - nowLen) + self.recvBufLen = nowLen + if nowLen < 4: + return + if (self.recvbuf[:4] != self.MAGIC_BYTES[self.network]) and (self.recvbuf[:4] != self.BTC_MAGIC_BYTES[self.network]): + raise ValueError("got garbage %s" % repr(self.recvbuf)) + if self.ver_recv < 209: + if len(self.recvbuf) < 4 + 12 + 4: + return + command = self.recvbuf[4:4 + 12].split(b"\x00", 1)[0] + msglen = struct.unpack("= 209: + th = sha256(data) + h = sha256(th) + tmsg += h[:4] + tmsg += data + with mininode_lock: + self.sendbuf += tmsg + self.last_sent = time.time() + + def got_message(self, message): + if message.command == b"version": + if message.nVersion <= BIP0031_VERSION: + self.messagemap[b'ping'] = msg_ping_prebip31 + if self.last_sent + 30 * 60 < time.time(): + self.send_message(self.messagemap[b'ping']()) + self.show_debug_msg("Recv %s" % repr(message)) + self.cb.deliver(self, message) + + def disconnect_node(self): + self.disconnect = True + + +class NetworkThread(Thread): + def run(self): + while mininode_socket_map: + # We check for whether to disconnect outside of the asyncore + # loop to workaround the behavior of asyncore when using + # select + disconnected = [] + for fd, obj in mininode_socket_map.items(): + if obj.disconnect: + disconnected.append(obj) + [obj.handle_close() for obj in disconnected] + asyncore.loop(0.1, use_poll=True, map=mininode_socket_map, count=1) + logging.info("mininode network processing thread completed") + + +# An exception we can raise if we detect a potential disconnect +# (p2p or rpc) before the test is complete +class EarlyDisconnectError(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return repr(self.value) diff --git a/qa/rpc-tests/test_framework/netutil.py b/qa/rpc-tests/test_framework/netutil.py new file mode 100644 index 00000000..a2718786 --- /dev/null +++ b/qa/rpc-tests/test_framework/netutil.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# Linux network utilities + +import sys +import socket +import fcntl +import struct +import array +import os +from binascii import unhexlify, hexlify + +# Roughly based on http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/ by Ricardo Pascal +STATE_ESTABLISHED = '01' +STATE_SYN_SENT = '02' +STATE_SYN_RECV = '03' +STATE_FIN_WAIT1 = '04' +STATE_FIN_WAIT2 = '05' +STATE_TIME_WAIT = '06' +STATE_CLOSE = '07' +STATE_CLOSE_WAIT = '08' +STATE_LAST_ACK = '09' +STATE_LISTEN = '0A' +STATE_CLOSING = '0B' + +def get_socket_inodes(pid): + ''' + Get list of socket inodes for process pid. + ''' + base = '/proc/%i/fd' % pid + inodes = [] + for item in os.listdir(base): + target = os.readlink(os.path.join(base, item)) + if target.startswith('socket:'): + inodes.append(int(target[8:-1])) + return inodes + +def _remove_empty(array): + return [x for x in array if x !=''] + +def _convert_ip_port(array): + host,port = array.split(':') + # convert host from mangled-per-four-bytes form as used by kernel + host = unhexlify(host) + host_out = '' + for x in range(0, len(host) // 4): + (val,) = struct.unpack('=I', host[x*4:(x+1)*4]) + host_out += '%08x' % val + + return host_out,int(port,16) + +def netstat(typ='tcp'): + ''' + Function to return a list with status of tcp connections at linux systems + To get pid of all network process running on system, you must run this script + as superuser + ''' + with open('/proc/net/'+typ,'r') as f: + content = f.readlines() + content.pop(0) + result = [] + for line in content: + line_array = _remove_empty(line.split(' ')) # Split lines and remove empty spaces. + tcp_id = line_array[0] + l_addr = _convert_ip_port(line_array[1]) + r_addr = _convert_ip_port(line_array[2]) + state = line_array[3] + inode = int(line_array[9]) # Need the inode to match with process pid. + nline = [tcp_id, l_addr, r_addr, state, inode] + result.append(nline) + return result + +def get_bind_addrs(pid): + ''' + Get bind addresses as (host,port) tuples for process pid. + ''' + inodes = get_socket_inodes(pid) + bind_addrs = [] + for conn in netstat('tcp') + netstat('tcp6'): + if conn[3] == STATE_LISTEN and conn[4] in inodes: + bind_addrs.append(conn[1]) + return bind_addrs + +# from: http://code.activestate.com/recipes/439093/ +def all_interfaces(): + ''' + Return all interfaces that are up + ''' + is_64bits = sys.maxsize > 2**32 + struct_size = 40 if is_64bits else 32 + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + max_possible = 8 # initial value + while True: + bytes = max_possible * struct_size + names = array.array('B', b'\0' * bytes) + outbytes = struct.unpack('iL', fcntl.ioctl( + s.fileno(), + 0x8912, # SIOCGIFCONF + struct.pack('iL', bytes, names.buffer_info()[0]) + ))[0] + if outbytes == bytes: + max_possible *= 2 + else: + break + namestr = names.tostring() + return [(namestr[i:i+16].split(b'\0', 1)[0], + socket.inet_ntoa(namestr[i+20:i+24])) + for i in range(0, outbytes, struct_size)] + +def addr_to_hex(addr): + ''' + Convert string IPv4 or IPv6 address to binary address as returned by + get_bind_addrs. + Very naive implementation that certainly doesn't work for all IPv6 variants. + ''' + if '.' in addr: # IPv4 + addr = [int(x) for x in addr.split('.')] + elif ':' in addr: # IPv6 + sub = [[], []] # prefix, suffix + x = 0 + addr = addr.split(':') + for i,comp in enumerate(addr): + if comp == '': + if i == 0 or i == (len(addr)-1): # skip empty component at beginning or end + continue + x += 1 # :: skips to suffix + assert(x < 2) + else: # two bytes per component + val = int(comp, 16) + sub[x].append(val >> 8) + sub[x].append(val & 0xff) + nullbytes = 16 - len(sub[0]) - len(sub[1]) + assert((x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0)) + addr = sub[0] + ([0] * nullbytes) + sub[1] + else: + raise ValueError('Could not parse address %s' % addr) + return hexlify(bytearray(addr)).decode('ascii') + +def test_ipv6_local(): + ''' + Check for (local) IPv6 support. + ''' + import socket + # By using SOCK_DGRAM this will not actually make a connection, but it will + # fail if there is no route to IPv6 localhost. + have_ipv6 = True + try: + s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + s.connect(('::1', 0)) + except socket.error: + have_ipv6 = False + return have_ipv6 diff --git a/qa/rpc-tests/test_framework/nodemessages.py b/qa/rpc-tests/test_framework/nodemessages.py new file mode 100644 index 00000000..9760fe18 --- /dev/null +++ b/qa/rpc-tests/test_framework/nodemessages.py @@ -0,0 +1,1092 @@ +import socket +import struct +import random +import hashlib +from binascii import hexlify, unhexlify +import time +from codecs import encode +from threading import RLock +from io import BytesIO +MY_VERSION = 60001 # past bip-31 for ping/pong +MY_SUBVERSION = b"/python-mininode-tester:0.0.3/" + +COIN = 100000000 # 1 btc in satoshis + +# One lock for synchronizing all data access between the networking thread (see +# NetworkThread below) and the thread running the test logic. For simplicity, +# NodeConn acquires this lock whenever delivering a message to to a NodeConnCB, +# and whenever adding anything to the send buffer (in send_message()). This +# lock should be acquired in the thread running the test logic to synchronize +# access to any data shared with the NodeConnCB or NodeConn. +mininode_lock = RLock() + +# 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 + + +# Serialization/deserialization tools +def sha256(s): + """Return the sha256 hash of the passed binary data + + >>> hexlify(sha256("e hat eye pie plus one is O".encode())) + b'c5b94099f454a3807377724eb99a33fbe9cb5813006cadc03e862a89d410eaf0' + """ + return hashlib.new('sha256', s).digest() + + +def hash256(s): + """Return the double SHA256 hash (what bitcoin typically uses) of the passed binary data + + >>> hexlify(hash256("There was a terrible ghastly silence".encode())) + b'730ac30b1e7f4061346277ab639d7a68c6686aeba4cc63280968b903024a0a40' + """ + return sha256(sha256(s)) + + +def deser_string(f): + """Convert an array of bytes in the bitcoin P2P protocol format into a string + + >>> import io + >>> deser_string(io.BytesIO(ser_string("The grid bug bites! You get zapped!".encode()))).decode() + 'The grid bug bites! You get zapped!' + """ + nit = struct.unpack(">> ser_string("The grid bug bites! You get zapped!".encode()) + b'$The grid bug bites! You get zapped!' + """ + if len(s) < 253: + return struct.pack("B", len(s)) + s + elif len(s) < 0x10000: + return struct.pack(">= 32 + return rs + + +def uint256_from_str(s): + r = 0 + t = struct.unpack("> 24) & 0xFF + v = (c & 0xFFFFFF) << (8 * (nbytes - 3)) + return v + + +def deser_vector(f, c): + nit = struct.unpack("H", f.read(2))[0] + + def serialize(self): + r = b"" + r += struct.pack("H", self.port) + return r + + def __repr__(self): + return "CAddress(nServices=%i ip=%s port=%i)" % (self.nServices, + self.ip, self.port) + + +class CInv(object): + MSG_TX = 1 + MSG_BLOCK = 2 + MSG_FILTERED_BLOCK = 3 + MSG_THINBLOCK = 4 + MSG_XTHINBLOCK = 5 + typemap = { + 0: "Error", + 1: "TX", + 2: "Block", + 3: "FilteredBlock", + 4: "ThinBlock", + 5: "XThinBlock", + } + + def __init__(self, t=0, h=0): + self.type = t + self.hash = h + + def deserialize(self, f): + self.type = struct.unpack(" 21000000 * COIN: + return False + return True + + def summary(self): + self.calc_sha256() + s = ["Transaction: %064x\n" % self.sha256] + s.append("%d inputs\n" % len(self.vin)) + for vin in self.vin: + s.append(" %064x.%d\n" % (vin.prevout.hash, vin.prevout.n)) + s.append("%d outputs\n" % len(self.vout)) + for vout in self.vout: + s.append(" %12d %s\n" % (vout.nValue, hexlify((vout.scriptPubKey)))) + return "".join(s) + + def __repr__(self): + return "CTransaction(nVersion=%i vin=%s vout=%s nLockTime=%i)" \ + % (self.nVersion, repr(self.vin), repr(self.vout), self.nLockTime) + + +class CBlockHeader(object): + def __init__(self, header=None): + if header is None: + self.set_null() + else: + self.nVersion = header.nVersion + self.hashPrevBlock = header.hashPrevBlock + self.hashMerkleRoot = header.hashMerkleRoot + self.nTime = header.nTime + self.nBits = header.nBits + self.nNonce = header.nNonce + self.sha256 = header.sha256 + self.hash = header.hash + self.calc_sha256() + + def set_null(self): + self.nVersion = 1 + self.hashPrevBlock = 0 + self.hashMerkleRoot = 0 + self.nTime = 0 + self.nBits = 0 + self.nNonce = 0 + self.sha256 = None + self.hash = None + + def deserialize(self, f): + self.nVersion = struct.unpack(" 1: + newhashes = [] + for i in range(0, len(hashes), 2): + i2 = min(i + 1, len(hashes) - 1) + newhashes.append(hash256(hashes[i] + hashes[i2])) + hashes = newhashes + if hashes: + return uint256_from_str(hashes[0]) + return 0 + + def is_valid(self): + self.calc_sha256() + target = uint256_from_compact(self.nBits) + if self.sha256 > target: + return False + for tx in self.vtx: + if not tx.is_valid(): + return False + if self.calc_merkle_root() != self.hashMerkleRoot: + return False + return True + + def solve(self): + self.rehash() + target = uint256_from_compact(self.nBits) + while self.sha256 > target: + self.nNonce += 1 + self.rehash() + + def __str__(self): + return "CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x vtx_len=%d)" \ + % (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot, + time.ctime(self.nTime), self.nBits, self.nNonce, len(self.vtx)) + + def __repr__(self): + return "CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x vtx=%s)" \ + % (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot, + time.ctime(self.nTime), self.nBits, self.nNonce, repr(self.vtx)) + + +class CUnsignedAlert(object): + def __init__(self): + self.nVersion = 1 + self.nRelayUntil = 0 + self.nExpiration = 0 + self.nID = 0 + self.nCancel = 0 + self.setCancel = [] + self.nMinVer = 0 + self.nMaxVer = 0 + self.setSubVer = [] + self.nPriority = 0 + self.strComment = b"" + self.strStatusBar = b"" + self.strReserved = b"" + + def deserialize(self, f): + self.nVersion = struct.unpack("= 106: + self.addrFrom = CAddress() + self.addrFrom.deserialize(f) + self.nNonce = struct.unpack("= 209: + self.nStartingHeight = struct.unpack(" + """ + command = b"headers" + + def __init__(self): + self.headers = [] + + def deserialize(self, f): + # comment in bitcoind indicates these should be deserialized as blocks + blocks = deser_vector(f, CBlock) + for x in blocks: + self.headers.append(CBlockHeader(x)) + + def serialize(self): + blocks = [CBlock(x) for x in self.headers] + return ser_vector(blocks) + + def __repr__(self): + return "msg_headers(headers=%s)" % repr(self.headers) + + +class msg_reject(object): + command = b"reject" + REJECT_MALFORMED = 1 + + def __init__(self): + self.message = b"" + self.code = 0 + self.reason = b"" + self.data = 0 + + def deserialize(self, f): + self.message = deser_string(f) + self.code = struct.unpack(" '3': + long = int + bchr = lambda x: bytes([x]) + bord = lambda x: x + +import struct + +from .bignum import bn2vch + +MAX_SCRIPT_SIZE = 10000 +MAX_SCRIPT_ELEMENT_SIZE = 520 +MAX_SCRIPT_OPCODES = 201 + +OPCODE_NAMES = {} + +_opcode_instances = [] +class CScriptOp(int): + """A single script opcode""" + __slots__ = [] + + @staticmethod + def encode_op_pushdata(d): + """Encode a PUSHDATA op, returning bytes""" + if len(d) < 0x4c: + return b'' + bchr(len(d)) + d # OP_PUSHDATA + elif len(d) <= 0xff: + return b'\x4c' + bchr(len(d)) + d # OP_PUSHDATA1 + elif len(d) <= 0xffff: + return b'\x4d' + struct.pack(b'>= 8 + if r[-1] & 0x80: + r.append(0x80 if neg else 0) + elif neg: + r[-1] |= 0x80 + return bytes(bchr(len(r)) + r) + + +class CScript(bytes): + """Serialized script + + A bytes subclass, so you can use this directly whenever bytes are accepted. + Note that this means that indexing does *not* work - you'll get an index by + byte rather than opcode. This format was chosen for efficiency so that the + general case would not require creating a lot of little CScriptOP objects. + + iter(script) however does iterate by opcode. + """ + @classmethod + def __coerce_instance(cls, other): + # Coerce other into bytes + if isinstance(other, CScriptOp): + other = bchr(other) + elif isinstance(other, CScriptNum): + if (other.value == 0): + other = bchr(CScriptOp(OP_0)) + else: + other = CScriptNum.encode(other) + elif isinstance(other, int): + if 0 <= other <= 16: + other = bytes(bchr(CScriptOp.encode_op_n(other))) + elif other == -1: + other = bytes(bchr(OP_1NEGATE)) + else: + other = CScriptOp.encode_op_pushdata(bn2vch(other)) + elif isinstance(other, (bytes, bytearray)): + other = CScriptOp.encode_op_pushdata(other) + return other + + def __add__(self, other): + # Do the coercion outside of the try block so that errors in it are + # noticed. + other = self.__coerce_instance(other) + + try: + # bytes.__add__ always returns bytes instances unfortunately + return CScript(super(CScript, self).__add__(other)) + except TypeError: + raise TypeError('Can not add a %r instance to a CScript' % other.__class__) + + def join(self, iterable): + # join makes no sense for a CScript() + raise NotImplementedError + + def __new__(cls, value=b''): + if isinstance(value, bytes) or isinstance(value, bytearray): + return super(CScript, cls).__new__(cls, value) + else: + def coerce_iterable(iterable): + for instance in iterable: + yield cls.__coerce_instance(instance) + # Annoyingly on both python2 and python3 bytes.join() always + # returns a bytes instance even when subclassed. + return super(CScript, cls).__new__(cls, b''.join(coerce_iterable(value))) + + def raw_iter(self): + """Raw iteration + + Yields tuples of (opcode, data, sop_idx) so that the different possible + PUSHDATA encodings can be accurately distinguished, as well as + determining the exact opcode byte indexes. (sop_idx) + """ + i = 0 + while i < len(self): + sop_idx = i + opcode = bord(self[i]) + i += 1 + + if opcode > OP_PUSHDATA4: + yield (opcode, None, sop_idx) + else: + datasize = None + pushdata_type = None + if opcode < OP_PUSHDATA1: + pushdata_type = 'PUSHDATA(%d)' % opcode + datasize = opcode + + elif opcode == OP_PUSHDATA1: + pushdata_type = 'PUSHDATA1' + if i >= len(self): + raise CScriptInvalidError('PUSHDATA1: missing data length') + datasize = bord(self[i]) + i += 1 + + elif opcode == OP_PUSHDATA2: + pushdata_type = 'PUSHDATA2' + if i + 1 >= len(self): + raise CScriptInvalidError('PUSHDATA2: missing data length') + datasize = bord(self[i]) + (bord(self[i+1]) << 8) + i += 2 + + elif opcode == OP_PUSHDATA4: + pushdata_type = 'PUSHDATA4' + if i + 3 >= len(self): + raise CScriptInvalidError('PUSHDATA4: missing data length') + datasize = bord(self[i]) + (bord(self[i+1]) << 8) + (bord(self[i+2]) << 16) + (bord(self[i+3]) << 24) + i += 4 + + else: + assert False # shouldn't happen + + + data = bytes(self[i:i+datasize]) + + # Check for truncation + if len(data) < datasize: + raise CScriptTruncatedPushDataError('%s: truncated data' % pushdata_type, data) + + i += datasize + + yield (opcode, data, sop_idx) + + def __iter__(self): + """'Cooked' iteration + + Returns either a CScriptOP instance, an integer, or bytes, as + appropriate. + + See raw_iter() if you need to distinguish the different possible + PUSHDATA encodings. + """ + for (opcode, data, sop_idx) in self.raw_iter(): + if data is not None: + yield data + else: + opcode = CScriptOp(opcode) + + if opcode.is_small_int(): + yield opcode.decode_op_n() + else: + yield CScriptOp(opcode) + + def __repr__(self): + # For Python3 compatibility add b before strings so testcases don't + # need to change + def _repr(o): + if isinstance(o, bytes): + return b"x('%s')" % hexlify(o).decode('ascii') + else: + return repr(o) + + ops = [] + i = iter(self) + while True: + op = None + try: + op = _repr(next(i)) + except CScriptTruncatedPushDataError as err: + op = '%s...' % (_repr(err.data), err) + break + except CScriptInvalidError as err: + op = '' % err + break + except StopIteration: + break + finally: + if op is not None: + ops.append(op) + + return "CScript([%s])" % ', '.join(ops) + + def GetSigOpCount(self, fAccurate): + """Get the SigOp count. + + fAccurate - Accurately count CHECKMULTISIG, see BIP16 for details. + + Note that this is consensus-critical. + """ + n = 0 + lastOpcode = OP_INVALIDOPCODE + for (opcode, data, sop_idx) in self.raw_iter(): + if opcode in (OP_CHECKSIG, OP_CHECKSIGVERIFY): + n += 1 + elif opcode in (OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY): + if fAccurate and (OP_1 <= lastOpcode <= OP_16): + n += opcode.decode_op_n() + else: + n += 20 + lastOpcode = opcode + return n + + +SIGHASH_ALL = 1 +SIGHASH_NONE = 2 +SIGHASH_SINGLE = 3 +SIGHASH_ANYONECANPAY = 0x80 + +def FindAndDelete(script, sig): + """Consensus critical, see FindAndDelete() in Satoshi codebase""" + r = b'' + last_sop_idx = sop_idx = 0 + skip = True + for (opcode, data, sop_idx) in script.raw_iter(): + if not skip: + r += script[last_sop_idx:sop_idx] + last_sop_idx = sop_idx + if script[sop_idx:sop_idx + len(sig)] == sig: + skip = True + else: + skip = False + if not skip: + r += script[last_sop_idx:] + return CScript(r) + + +def SignatureHash(script, txTo, inIdx, hashtype): + """Consensus-correct SignatureHash + + Returns (hash, err) to precisely match the consensus-critical behavior of + the SIGHASH_SINGLE bug. (inIdx is *not* checked for validity) + """ + HASH_ONE = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + + if inIdx >= len(txTo.vin): + return (HASH_ONE, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin))) + txtmp = CTransaction(txTo) + + for txin in txtmp.vin: + txin.scriptSig = b'' + txtmp.vin[inIdx].scriptSig = FindAndDelete(script, CScript([OP_CODESEPARATOR])) + + if (hashtype & 0x1f) == SIGHASH_NONE: + txtmp.vout = [] + + for i in range(len(txtmp.vin)): + if i != inIdx: + txtmp.vin[i].nSequence = 0 + + elif (hashtype & 0x1f) == SIGHASH_SINGLE: + outIdx = inIdx + if outIdx >= len(txtmp.vout): + return (HASH_ONE, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout))) + + tmp = txtmp.vout[outIdx] + txtmp.vout = [] + for i in range(outIdx): + txtmp.vout.append(CTxOut()) + txtmp.vout.append(tmp) + + for i in range(len(txtmp.vin)): + if i != inIdx: + txtmp.vin[i].nSequence = 0 + + if hashtype & SIGHASH_ANYONECANPAY: + tmp = txtmp.vin[inIdx] + txtmp.vin = [] + txtmp.vin.append(tmp) + + s = txtmp.serialize() + s += struct.pack(b" 0: + d = s.recv(n) + if not d: + raise IOError('Unexpected end of stream') + rv.extend(d) + n -= len(d) + return rv + +### Implementation classes +class Socks5Configuration(object): + '''Proxy configuration''' + def __init__(self): + self.addr = None # Bind address (must be set) + self.af = socket.AF_INET # Bind address family + self.unauth = False # Support unauthenticated + self.auth = False # Support authentication + +class Socks5Command(object): + '''Information about an incoming socks5 command''' + def __init__(self, cmd, atyp, addr, port, username, password): + self.cmd = cmd # Command (one of Command.*) + self.atyp = atyp # Address type (one of AddressType.*) + self.addr = addr # Address + self.port = port # Port to connect to + self.username = username + self.password = password + def __repr__(self): + return 'Socks5Command(%s,%s,%s,%s,%s,%s)' % (self.cmd, self.atyp, self.addr, self.port, self.username, self.password) + +class Socks5Connection(object): + def __init__(self, serv, conn, peer): + self.serv = serv + self.conn = conn + self.peer = peer + + def handle(self): + ''' + Handle socks5 request according to RFC1928 + ''' + try: + # Verify socks version + ver = recvall(self.conn, 1)[0] + if ver != 0x05: + raise IOError('Invalid socks version %i' % ver) + # Choose authentication method + nmethods = recvall(self.conn, 1)[0] + methods = bytearray(recvall(self.conn, nmethods)) + method = None + if 0x02 in methods and self.serv.conf.auth: + method = 0x02 # username/password + elif 0x00 in methods and self.serv.conf.unauth: + method = 0x00 # unauthenticated + if method is None: + raise IOError('No supported authentication method was offered') + # Send response + self.conn.sendall(bytearray([0x05, method])) + # Read authentication (optional) + username = None + password = None + if method == 0x02: + ver = recvall(self.conn, 1)[0] + if ver != 0x01: + raise IOError('Invalid auth packet version %i' % ver) + ulen = recvall(self.conn, 1)[0] + username = str(recvall(self.conn, ulen)) + plen = recvall(self.conn, 1)[0] + password = str(recvall(self.conn, plen)) + # Send authentication response + self.conn.sendall(bytearray([0x01, 0x00])) + + # Read connect request + (ver,cmd,rsv,atyp) = recvall(self.conn, 4) + if ver != 0x05: + raise IOError('Invalid socks version %i in connect request' % ver) + if cmd != Command.CONNECT: + raise IOError('Unhandled command %i in connect request' % cmd) + + if atyp == AddressType.IPV4: + addr = recvall(self.conn, 4) + elif atyp == AddressType.DOMAINNAME: + n = recvall(self.conn, 1)[0] + addr = recvall(self.conn, n) + elif atyp == AddressType.IPV6: + addr = recvall(self.conn, 16) + else: + raise IOError('Unknown address type %i' % atyp) + port_hi,port_lo = recvall(self.conn, 2) + port = (port_hi << 8) | port_lo + + # Send dummy response + self.conn.sendall(bytearray([0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + + cmdin = Socks5Command(cmd, atyp, addr, port, username, password) + self.serv.queue.put(cmdin) + print('Proxy: ', cmdin) + # Fall through to disconnect + except Exception as e: + traceback.print_exc(file=sys.stderr) + self.serv.queue.put(e) + finally: + self.conn.close() + +class Socks5Server(object): + def __init__(self, conf): + self.conf = conf + + # auto retry binding to subsequent ports - a port might be in + # use by other processing running on the OS during testing. This + # should reduce sporadic failures due to 'address in use'. + # Note that this implicitly auto-changes the socket configuration. + for i in range(1, 6): + try: + self.s = socket.socket(conf.af) + self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.s.bind(conf.addr) + self.s.listen(5) + break + except OSError as e: + if "Address already in use" not in str(e): + raise + else: + print("Warning: Address in use:", conf.addr) + conf.addr = (conf.addr[0], conf.addr[1] + i) + print("Warning: Attempting to use address:", conf.addr) + + self.running = False + self.thread = None + self.queue = queue.Queue() # report connections and exceptions to client + + def run(self): + while self.running: + (sockconn, peer) = self.s.accept() + if self.running: + conn = Socks5Connection(self, sockconn, peer) + thread = threading.Thread(None, conn.handle) + thread.daemon = True + thread.start() + + def start(self): + assert(not self.running) + self.running = True + self.thread = threading.Thread(None, self.run) + self.thread.daemon = True + self.thread.start() + + def stop(self): + self.running = False + # connect to self to end run loop + s = socket.socket(self.conf.af) + s.connect(self.conf.addr) + s.close() + self.thread.join() diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py new file mode 100644 index 00000000..9f2e943c --- /dev/null +++ b/qa/rpc-tests/test_framework/test_framework.py @@ -0,0 +1,277 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# Base class for RPC testing + +import logging +import optparse +import os +import sys +import time # BU added +import random # BU added +import pdb # BU added +import shutil +import tempfile +import traceback + +from .util import ( + initialize_chain, + assert_equal, + start_nodes, + connect_nodes_bi, + sync_blocks, + sync_mempools, + stop_nodes, + wait_bitcoinds, + enable_coverage, + check_json_precision, + initialize_chain_clean, + PortSeed, +) +from .authproxy import JSONRPCException + + +class BitcoinTestFramework(object): + drop_to_pdb = os.getenv("DROP_TO_PDB", "") + + # These may be over-ridden by subclasses: + def run_test(self): + for node in self.nodes: + assert_equal(node.getblockcount(), 200) + assert_equal(node.getbalance(), 25*50) + + def add_options(self, parser): + pass + + def setup_chain(self,bitcoinConfDict=None, wallets=None): + """ + Sets up the blockchain for the bitcoin nodes. It also sets up the daemon configuration. + bitcoinConfDict: Pass a dictionary of values you want written to bitcoin.conf. If you have a key with multiple values, pass a list of the values as the value, for example: + { "debug":["net","blk","thin","lck","mempool","req","bench","evict"] } + This framework provides values for the necessary fields (like regtest=1). But you can override these + defaults by setting them in this dictionary. + + wallets: Pass a list of wallet filenames. Each wallet file will be copied into the node's directory + before starting the node. + """ + print("Initializing test directory ", self.options.tmpdir, "Bitcoin conf: ", str(bitcoinConfDict), "walletfiles: ", wallets) + initialize_chain(self.options.tmpdir,bitcoinConfDict, wallets) + + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir) + + def setup_network(self, split = False): + self.nodes = self.setup_nodes() + + # Connect the nodes as a "chain". This allows us + # to split the network between nodes 1 and 2 to get + # two halves that can work on competing chains. + + # If we joined network halves, connect the nodes from the joint + # on outward. This ensures that chains are properly reorganised. + if not split: + connect_nodes_bi(self.nodes, 1, 2) + sync_blocks(self.nodes[1:3]) + sync_mempools(self.nodes[1:3]) + + connect_nodes_bi(self.nodes, 0, 1) + connect_nodes_bi(self.nodes, 2, 3) + self.is_network_split = split + self.sync_all() + + def split_network(self): + """ + Split the network of four nodes into nodes 0/1 and 2/3. + """ + assert not self.is_network_split + stop_nodes(self.nodes) + wait_bitcoinds() + self.setup_network(True) + + def sync_all(self): + """Synchronizes blocks and mempools""" + if self.is_network_split: + sync_blocks(self.nodes[:2]) + sync_blocks(self.nodes[2:]) + sync_mempools(self.nodes[:2]) + sync_mempools(self.nodes[2:]) + else: + sync_blocks(self.nodes) + sync_mempools(self.nodes) + + def sync_blocks(self): + """Synchronizes blocks""" + if self.is_network_split: + sync_blocks(self.nodes[:2]) + sync_blocks(self.nodes[2:]) + else: + sync_blocks(self.nodes) + + def join_network(self): + """ + Join the (previously split) network halves together. + """ + assert self.is_network_split + stop_nodes(self.nodes) + wait_bitcoinds() + self.setup_network(False) + + def main(self,argsOverride=None,bitcoinConfDict=None,wallets=None): + """ + argsOverride: pass your own values for sys.argv in this field (or pass None) to use sys.argv + bitcoinConfDict: Pass a dictionary of values you want written to bitcoin.conf. If you have a key with multiple values, pass a list of the values as the value, for example: + { "debug":["net","blk","thin","lck","mempool","req","bench","evict"] } + This framework provides values for the necessary fields (like regtest=1). But you can override these + defaults by setting them in this dictionary. + + wallets: Pass a list of wallet filenames. Each wallet file will be copied into the node's directory + before starting the node. + """ + import optparse + + parser = optparse.OptionParser(usage="%prog [options]") + parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true", + help="Leave bitcoinds and test.* datadir on exit or error") + parser.add_option("--noshutdown", dest="noshutdown", default=False, action="store_true", + help="Don't stop bitcoinds after the test execution") + parser.add_option("--srcdir", dest="srcdir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__))+"/../../../src"), + help="Source directory containing bitcoind/bitcoin-cli (default: %default)") + parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"), + help="Root directory for datadirs") + parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true", + help="Print out all RPC calls as they are made") + parser.add_option("--portseed", dest="port_seed", default=os.getpid(), type='int', + help="The seed to use for assigning port numbers (default: current process id)") + parser.add_option("--coveragedir", dest="coveragedir", + help="Write tested RPC commands into this directory") + # BU: added for tests using randomness (e.g. excessive.py) + parser.add_option("--randomseed", dest="randomseed", + help="Set RNG seed for tests that use randomness (ignored otherwise)") + self.add_options(parser) + (self.options, self.args) = parser.parse_args(argsOverride) + + # BU: initialize RNG seed based on time if no seed specified + if self.options.randomseed: + self.randomseed = int(self.options.randomseed) + else: + self.randomseed = int(time.time()) + random.seed(self.randomseed) + print("Random seed: %s" % self.randomseed) + + self.options.tmpdir = os.path.join(self.options.tmpdir, str(self.options.port_seed)) + + if self.options.trace_rpc: + logging.basicConfig(level=logging.DEBUG, stream=sys.stdout) + + if self.options.coveragedir: + enable_coverage(self.options.coveragedir) + + PortSeed.n = self.options.port_seed + + os.environ['PATH'] = self.options.srcdir + ":" + os.path.join(self.options.srcdir, "qt") + ":" + os.environ['PATH'] + + check_json_precision() + + success = False + try: + os.makedirs(self.options.tmpdir, exist_ok=False) + + # Not pretty but, I changed the function signature + # of setup_chain to allow customization of the setup. + # However derived object may still use the old format + if self.setup_chain.__defaults__ is None: + self.setup_chain() + else: + self.setup_chain(bitcoinConfDict, wallets) + + self.setup_network() + self.run_test() + success = True + except JSONRPCException as e: + print("JSONRPC error: "+e.error['message']) + typ, value, tb = sys.exc_info() + traceback.print_tb(tb) + if self.drop_to_pdb: pdb.post_mortem(tb) + except AssertionError as e: + print("Assertion failed: " + str(e)) + typ, value, tb = sys.exc_info() + traceback.print_tb(tb) + if self.drop_to_pdb: pdb.post_mortem(tb) + except KeyError as e: + print("key not found: "+ str(e)) + typ, value, tb = sys.exc_info() + traceback.print_tb(tb) + if self.drop_to_pdb: pdb.post_mortem(tb) + except Exception as e: + print("Unexpected exception caught during testing: " + repr(e)) + typ, value, tb = sys.exc_info() + traceback.print_tb(tb) + if self.drop_to_pdb: pdb.post_mortem(tb) + except KeyboardInterrupt as e: + print("Exiting after " + repr(e)) + + if not self.options.noshutdown: + print("Stopping nodes") + stop_nodes(self.nodes) + wait_bitcoinds() + else: + print("Note: bitcoinds were not stopped and may still be running") + + if not self.options.nocleanup and not self.options.noshutdown and success: + print("Cleaning up") + shutil.rmtree(self.options.tmpdir) + + else: + print("Not cleaning up dir %s" % self.options.tmpdir) + if os.getenv("PYTHON_DEBUG", ""): + # Dump the end of the debug logs, to aid in debugging rare + # travis failures. + import glob + filenames = glob.glob(self.options.tmpdir + "/node*/regtest/debug.log") + MAX_LINES_TO_PRINT = 1000 + for f in filenames: + print("From" , f, ":") + from collections import deque + print("".join(deque(open(f), MAX_LINES_TO_PRINT))) + + if success: + print("Tests successful") + sys.exit(0) + else: + print("Failed") + sys.exit(1) + + +# Test framework for doing p2p comparison testing, which sets up some bitcoind +# binaries: +# 1 binary: test binary +# 2 binaries: 1 test binary, 1 ref binary +# n>2 binaries: 1 test binary, n-1 ref binaries + +class ComparisonTestFramework(BitcoinTestFramework): + + # Can override the num_nodes variable to indicate how many nodes to run. + def __init__(self): + self.num_nodes = 2 + + def add_options(self, parser): + parser.add_option("--testbinary", dest="testbinary", + default=os.getenv("BITCOIND", "bitcoind"), + help="bitcoind binary to test") + parser.add_option("--refbinary", dest="refbinary", + default=os.getenv("BITCOIND", "bitcoind"), + help="bitcoind binary to use for reference nodes (if any)") + + def setup_chain(self,bitcoinConfDict=None, wallets=None): # BU add config params + print("Initializing test directory ", self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, self.num_nodes,bitcoinConfDict, wallets) + + def setup_network(self): + self.nodes = start_nodes( + self.num_nodes, self.options.tmpdir, + extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes, + binary=[self.options.testbinary] + + [self.options.refbinary]*(self.num_nodes-1)) diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py new file mode 100644 index 00000000..07fad09a --- /dev/null +++ b/qa/rpc-tests/test_framework/util.py @@ -0,0 +1,752 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +# +# Helpful routines for regression testing +# +import pdb +# Add python-bitcoinrpc to module search path: +import os +import sys +import math +import binascii +from binascii import hexlify, unhexlify +from base64 import b64encode +from decimal import Decimal, ROUND_DOWN +import decimal +import json +import http.client +import random +import shutil +import subprocess +import time +import re +import urllib.parse as urlparse +import errno +import logging + +from . import coverage +from .authproxy import AuthServiceProxy, JSONRPCException + +COVERAGE_DIR = None + +DEFAULT_TX_FEE_PER_BYTE = 50 +PerfectFractions = True +BTC = 100000000 +mBTC = 100000 +uBTC = 100 +# The maximum number of nodes a single test can spawn +MAX_NODES = 8 +# Don't assign rpc or p2p ports lower than this +PORT_MIN = 11000 +# The number of ports to "reserve" for p2p and rpc, each +PORT_RANGE = 5000 + + +class PortSeed: + # Must be initialized with a unique integer for each process + n = None + +#Set Mocktime default to OFF. +#MOCKTIME is only needed for scripts that use the +#cached version of the blockchain. If the cached +#version of the blockchain is used without MOCKTIME +#then the mempools will not sync due to IBD. +MOCKTIME = 0 + +def enable_mocktime(): + # Set the mocktime to be after the Bitcoin Cash fork so + # in normal tests blockchains the fork is in the past + global MOCKTIME + MOCKTIME = 1501600000 + (201 * 10 * 60) + +def disable_mocktime(): + global MOCKTIME + MOCKTIME = 0 + +def get_mocktime(): + return MOCKTIME + +def enable_coverage(dirname): + """Maintain a log of which RPC calls are made during testing.""" + global COVERAGE_DIR + COVERAGE_DIR = dirname + + +def get_rpc_proxy(url, node_number, timeout=None): + """ + Args: + url (str): URL of the RPC server to call + node_number (int): the node number (or id) that this calls to + + Kwargs: + timeout (int): HTTP timeout in seconds + + Returns: + AuthServiceProxy. convenience object for making RPC calls. + + """ + proxy_kwargs = {} + if timeout is not None: + proxy_kwargs['timeout'] = timeout + + proxy = AuthServiceProxy(url, **proxy_kwargs) + proxy.url = url # store URL on proxy for info + + coverage_logfile = coverage.get_filename( + COVERAGE_DIR, node_number) if COVERAGE_DIR else None + + return coverage.AuthServiceProxyWrapper(proxy, coverage_logfile) + + +def p2p_port(n): + assert(n <= MAX_NODES) + return PORT_MIN + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES) + +def rpc_port(n): + return PORT_MIN + PORT_RANGE + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES) + +def check_json_precision(): + """Make sure json library being used does not lose precision converting BTC values""" + n = Decimal("20000000.00000003") + satoshis = int(json.loads(json.dumps(float(n)))*1.0e8) + if satoshis != 2000000000000003: + raise RuntimeError("JSON encode/decode loses precision") + +def count_bytes(hex_string): + return len(bytearray.fromhex(hex_string)) + +def bytes_to_hex_str(byte_str): + return hexlify(byte_str).decode('ascii') + +def hex_str_to_bytes(hex_str): + return unhexlify(hex_str.encode('ascii')) + +def str_to_b64str(string): + return b64encode(string.encode('utf-8')).decode('ascii') + +def sync_blocks(rpc_connections, wait=1,verbose=1): + """ + Wait until everybody has the same block count + """ + while True: + counts = [ x.getblockcount() for x in rpc_connections ] + if verbose: + logging.info("sync blocks: " + str(counts)) + if counts == [ counts[0] ]*len(counts): + break + time.sleep(wait) + +def sync_mempools(rpc_connections, wait=1,verbose=1): + """ + Wait until everybody has the same transactions in their memory + pools + """ + count = 0 + while True: + count += 1 + pool = set(rpc_connections[0].getrawmempool()) + num_match = 1 + pool_len = [len(pool)] + for i in range(1, len(rpc_connections)): + tmp = set(rpc_connections[i].getrawmempool()) + if tmp == pool: + num_match = num_match+1 + pool_len.append(len(tmp)) + if verbose and count%30==0: + logging.info("sync mempool: " + str(pool_len)) + if num_match == len(rpc_connections): + break + time.sleep(wait) + +bitcoind_processes = {} + +def initialize_datadir(dirname, n,bitcoinConfDict=None,wallet=None): + datadir = os.path.join(dirname, "node"+str(n)) + if not os.path.isdir(datadir): + os.makedirs(datadir) + + defaults = {"server":1, "discover":0, "regtest":1,"rpcuser":"rt","rpcpassword":"rt", + "port":p2p_port(n),"rpcport":str(rpc_port(n)),"listenonion":0,"maxlimitertxfee":0} + if bitcoinConfDict: defaults.update(bitcoinConfDict) + + with open(os.path.join(datadir, "bitcoin.conf"), 'w') as f: + for (key,val) in defaults.items(): + if type(val) is type([]): + for v in val: + f.write("%s=%s\n" % (str(key), str(v))) + else: + f.write("%s=%s\n"% (str(key), str(val))) + + if wallet: + regtestdir = os.path.join(datadir,"regtest") + if not os.path.isdir(regtestdir): + os.makedirs(regtestdir) + print(regtestdir, os.path.join(regtestdir, "wallet.dat")) + shutil.copyfile(wallet,os.path.join(regtestdir, "wallet.dat")) + + return datadir + +def rpc_url(i, rpchost=None): + return "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i)) + +def wait_for_bitcoind_start(process, url, i): + ''' + Wait for bitcoind to start. This means that RPC is accessible and fully initialized. + Raise an exception if bitcoind exits during initialization. + ''' + while True: + if process.poll() is not None: + raise Exception('bitcoind exited with status %i during initialization' % process.returncode) + try: + rpc = get_rpc_proxy(url, i) + blocks = rpc.getblockcount() + break # break out of loop on success + except IOError as e: + if e.errno != errno.ECONNREFUSED: # Port not yet open? + raise # unknown IO error + except JSONRPCException as e: # Initialization phase + if e.error['code'] != -28: # RPC in warmup? + raise # unkown JSON RPC exception + time.sleep(0.25) + +def initialize_chain(test_dir,bitcoinConfDict=None,wallets=None): + """ + Create (or copy from cache) a 200-block-long chain and + 4 wallets. + """ + + if (not os.path.isdir(os.path.join("cache","node0")) + or not os.path.isdir(os.path.join("cache","node1")) + or not os.path.isdir(os.path.join("cache","node2")) + or not os.path.isdir(os.path.join("cache","node3"))): + + #find and delete old cache directories if any exist + for i in range(4): + if os.path.isdir(os.path.join("cache","node"+str(i))): + shutil.rmtree(os.path.join("cache","node"+str(i))) + + # Create cache directories, run bitcoinds: + for i in range(4): + datadir=initialize_datadir("cache", i,bitcoinConfDict) + args = [ os.getenv("BITCOIND", "bitcoind"), "-keypool=1", "-datadir="+datadir ] + if i > 0: + args.append("-connect=127.0.0.1:"+str(p2p_port(0))) + bitcoind_processes[i] = subprocess.Popen(args) + if os.getenv("PYTHON_DEBUG", ""): + print("initialize_chain: bitcoind started, waiting for RPC to come up") + wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i) + if os.getenv("PYTHON_DEBUG", ""): + print("initialize_chain: RPC succesfully started") + + rpcs = [] + for i in range(4): + try: + rpcs.append(get_rpc_proxy(rpc_url(i), i)) + except: + sys.stderr.write("Error connecting to "+url+"\n") + sys.exit(1) + + # Create a 200-block-long chain; each of the 4 nodes + # gets 25 mature blocks and 25 immature. + # blocks are created with timestamps 10 minutes apart + # starting from 2010 minutes in the past + enable_mocktime() + block_time = get_mocktime() - (201 * 10 * 60) + for i in range(2): + for peer in range(4): + for j in range(25): + set_node_times(rpcs, block_time) + rpcs[peer].generate(1) + block_time += 10*60 + # Must sync before next peer starts generating blocks + sync_blocks(rpcs) + + # Shut them down, and clean up cache directories: + stop_nodes(rpcs) + wait_bitcoinds() + disable_mocktime() + for i in range(4): + os.remove(log_filename("cache", i, "debug.log")) + os.remove(log_filename("cache", i, "db.log")) + os.remove(log_filename("cache", i, "peers.dat")) + os.remove(log_filename("cache", i, "fee_estimates.dat")) + + for i in range(4): + from_dir = os.path.join("cache", "node"+str(i)) + to_dir = os.path.join(test_dir, "node"+str(i)) + shutil.copytree(from_dir, to_dir) + initialize_datadir(test_dir, i,bitcoinConfDict,wallets[i] if wallets else None) # Overwrite port/rpcport in bitcoin.conf + +def initialize_chain_clean(test_dir, num_nodes, bitcoinConfDict=None, wallets=None): + """ + Create an empty blockchain and num_nodes wallets. + Useful if a test case wants complete control over initialization. + """ + for i in range(num_nodes): + datadir=initialize_datadir(test_dir, i, bitcoinConfDict, wallets) + + +def _rpchost_to_args(rpchost): + '''Convert optional IP:port spec to rpcconnect/rpcport args''' + if rpchost is None: + return [] + + match = re.match('(\[[0-9a-fA-f:]+\]|[^:]+)(?::([0-9]+))?$', rpchost) + if not match: + raise ValueError('Invalid RPC host spec ' + rpchost) + + rpcconnect = match.group(1) + rpcport = match.group(2) + + if rpcconnect.startswith('['): # remove IPv6 [...] wrapping + rpcconnect = rpcconnect[1:-1] + + rv = ['-rpcconnect=' + rpcconnect] + if rpcport: + rv += ['-rpcport=' + rpcport] + return rv + +def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None): + """ + Start a bitcoind and return RPC connection to it + """ + datadir = os.path.join(dirname, "node"+str(i)) + if binary is None: + binary = os.getenv("BITCOIND", "bitcoind") + # RPC tests still depend on free transactions + args = [ binary, "-datadir="+datadir, "-rest", "-mocktime="+str(get_mocktime()) ] # // BU removed, "-keypool=1","-blockprioritysize=50000" ] + if extra_args is not None: args.extend(extra_args) + bitcoind_processes[i] = subprocess.Popen(args) + if os.getenv("PYTHON_DEBUG", ""): + print("start_node: bitcoind started, waiting for RPC to come up") + url = rpc_url(i, rpchost) + wait_for_bitcoind_start(bitcoind_processes[i], url, i) + if os.getenv("PYTHON_DEBUG", ""): + print("start_node: RPC succesfully started") + proxy = get_rpc_proxy(url, i, timeout=timewait) + + if COVERAGE_DIR: + coverage.write_all_rpc_commands(COVERAGE_DIR, proxy) + + return proxy + +def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None,timewait=None): + """ + Start multiple bitcoinds, return RPC connections to them + """ + if extra_args is None: extra_args = [ None for _ in range(num_nodes) ] + if binary is None: binary = [ None for _ in range(num_nodes) ] + rpcs = [] + try: + for i in range(num_nodes): + rpcs.append(start_node(i, dirname, extra_args[i], rpchost, binary=binary[i],timewait=timewait)) + except: # If one node failed to start, stop the others + stop_nodes(rpcs) + raise + return rpcs + +def log_filename(dirname, n_node, logname): + return os.path.join(dirname, "node"+str(n_node), "regtest", logname) + +def stop_node(node, i): + try: + node.stop() + except http.client.CannotSendRequest as e: + print("WARN: Unable to stop node: " + repr(e)) + bitcoind_processes[i].wait() + del bitcoind_processes[i] + +def stop_nodes(nodes): + for node in nodes: + try: + node.stop() + except http.client.CannotSendRequest as e: + print("WARN: Unable to stop node: " + repr(e)) + del nodes[:] # Emptying array closes connections as a side effect + +def set_node_times(nodes, t): + for node in nodes: + node.setmocktime(t) + +def wait_bitcoinds(): + # Wait for all bitcoinds to cleanly exit + for bitcoind in bitcoind_processes.values(): + bitcoind.wait() + bitcoind_processes.clear() + +def connect_nodes(from_connection, node_num): + ip_port = "127.0.0.1:"+str(p2p_port(node_num)) + from_connection.addnode(ip_port, "onetry") + # poll until version handshake complete to avoid race conditions + # with transaction relaying + while any(peer['version'] == 0 for peer in from_connection.getpeerinfo()): + time.sleep(0.1) + +def connect_nodes_bi(nodes, a, b): + connect_nodes(nodes[a], b) + connect_nodes(nodes[b], a) + +def interconnect_nodes(nodes): + """Connect every node in this list to every other node in the list""" + for frm in nodes: + for to in nodes: + if frm == to: continue + up = urlparse.urlparse(to.url) + ip_port = up.hostname + ":" + str(up.port - PORT_RANGE) # this is the RPC port but we want the p2p port so -1000 + frm.addnode(ip_port, "onetry") + +def find_output(node, txid, amount): + """ + Return index to output of txid with value amount + Raises exception if there is none. + """ + txdata = node.getrawtransaction(txid, 1) + for i in range(len(txdata["vout"])): + if txdata["vout"][i]["value"] == amount: + return i + raise RuntimeError("find_output txid %s : %s not found"%(txid,str(amount))) + + +def gather_inputs(from_node, amount_needed, confirmations_required=1): + """ + Return a random set of unspent txouts that are enough to pay amount_needed + """ + assert(confirmations_required >=0) + utxo = from_node.listunspent(confirmations_required) + random.shuffle(utxo) + inputs = [] + total_in = Decimal("0.00000000") + while total_in < amount_needed and len(utxo) > 0: + t = utxo.pop() + total_in += t["amount"] + inputs.append({ "txid" : t["txid"], "vout" : t["vout"], "address" : t["address"] } ) + if total_in < amount_needed: + raise RuntimeError("Insufficient funds: need %d, have %d"%(amount_needed, total_in)) + return (total_in, inputs) + +def make_change(from_node, amount_in, amount_out, fee): + """ + Create change output(s), return them + """ + outputs = {} + amount = amount_out+fee + change = amount_in - amount + if change > amount*2: + # Create an extra change output to break up big inputs + change_address = from_node.getnewaddress() + # Split change in two, being careful of rounding: + outputs[change_address] = Decimal(change/2).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) + change = amount_in - amount - outputs[change_address] + if change > 0: + outputs[from_node.getnewaddress()] = change + return outputs + +def send_zeropri_transaction(from_node, to_node, amount, fee): + """ + Create&broadcast a zero-priority transaction. + Returns (txid, hex-encoded-txdata) + Ensures transaction is zero-priority by first creating a send-to-self, + then using its output + """ + + # Create a send-to-self with confirmed inputs: + self_address = from_node.getnewaddress() + (total_in, inputs) = gather_inputs(from_node, amount+fee*2) + outputs = make_change(from_node, total_in, amount+fee, fee) + outputs[self_address] = float(amount+fee) + + self_rawtx = from_node.createrawtransaction(inputs, outputs) + self_signresult = from_node.signrawtransaction(self_rawtx) + self_txid = from_node.sendrawtransaction(self_signresult["hex"], True) + + vout = find_output(from_node, self_txid, amount+fee) + # Now immediately spend the output to create a 1-input, 1-output + # zero-priority transaction: + inputs = [ { "txid" : self_txid, "vout" : vout } ] + outputs = { to_node.getnewaddress() : float(amount) } + + rawtx = from_node.createrawtransaction(inputs, outputs) + signresult = from_node.signrawtransaction(rawtx) + txid = from_node.sendrawtransaction(signresult["hex"], True) + + return (txid, signresult["hex"]) + +def random_zeropri_transaction(nodes, amount, min_fee, fee_increment, fee_variants): + """ + Create a random zero-priority transaction. + Returns (txid, hex-encoded-transaction-data, fee) + """ + from_node = random.choice(nodes) + to_node = random.choice(nodes) + fee = min_fee + fee_increment*random.randint(0,fee_variants) + (txid, txhex) = send_zeropri_transaction(from_node, to_node, amount, fee) + return (txid, txhex, fee) + +def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants): + """ + Create a random transaction. + Returns (txid, hex-encoded-transaction-data, fee) + """ + from_node = random.choice(nodes) + to_node = random.choice(nodes) + fee = min_fee + fee_increment*random.randint(0,fee_variants) + + (total_in, inputs) = gather_inputs(from_node, amount+fee) + outputs = make_change(from_node, total_in, amount, fee) + outputs[to_node.getnewaddress()] = float(amount) + + rawtx = from_node.createrawtransaction(inputs, outputs) + signresult = from_node.signrawtransaction(rawtx) + txid = from_node.sendrawtransaction(signresult["hex"], True) + + return (txid, signresult["hex"], fee) + +def split_transaction(node, prevouts, toAddrs, txfeePer=DEFAULT_TX_FEE_PER_BYTE,**kwargs): + """ + Create a transaction that divides the sum of all the passed utxos into all the destination addresses + pass: + node: (node object) where to send the RPC calls + prevouts: a single UTXO description dictionary, or a list of them + toAddrs: a list of strings specifying the output addresses + "sendtx=False" if you don't want to transaction to be submitted. + Returns (transaction in hex, Vin list, Vout list) + """ + if type(prevouts) == type({}): prevouts = [prevouts] # If the user passes just one transaction then put a list around it + txid = None + inp = [] + decContext = decimal.getcontext().prec + try: # try finally block to put the decimal precision back to what it was prior to this routine + decimal.getcontext().prec = 8 + 8 # 8 digits to get to 21million, and each bitcoin is 100 million satoshis + amount = Decimal(0) + iamount = 0 + count = 0 + for tx in prevouts: + inp.append({"txid":str(tx["txid"]),"vout":tx["vout"]}) + amount += tx["amount"]*Decimal(BTC) + iamount += int(tx["amount"]*Decimal(BTC)) + count += 1 + + assert(amount == iamount) # make sure Decimal and integer math is consistent + txLen = (len(prevouts)*100) + (len(toAddrs)*100) # Guess the tx Size + + while 1: + outp = {} + if amount - Decimal(txfeePer*txLen) < 0: # fee too big, find something smaller + txfeePer = (float(amount)/txLen)/1.5 + + txfee = int(math.ceil(txfeePer*txLen)) + amtPer = (Decimal(amount-txfee)/len(toAddrs)).to_integral_value() + # print "amount: ", amount, " amount per: ", amtPer, "from :", len(prevouts), "to: ", len(toAddrs), "tx fee: ", txfeePer, txfee + + for a in toAddrs[0:-1]: + if PerfectFractions: + outp[str(a)] = str(amtPer/Decimal(BTC)) + else: + outp[str(a)] = float(amtPer/BTC) + + a = toAddrs[-1] + amtPer = (amount - ((len(toAddrs)-1)*amtPer)) - txfee + # print "final amt: ", amtPer + if PerfectFractions: + outp[str(a)] = str(amtPer/BTC) + else: + outp[str(a)] = float(amtPer/BTC) + + totalOutputs = sum([Decimal(x) for x in outp.values()]) + assert(totalOutputs < amount) + txn = node.createrawtransaction(inp, outp) + if kwargs.get("sendtx",True): + #print time.strftime('%X %x %Z') + try: + s = str(txn) + # print "tx len: ", len(binascii.unhexlify(s)) + signedtxn = node.signrawtransaction(s) + txLen = len(binascii.unhexlify(signedtxn["hex"])) # Get the actual transaction size for better tx fee estimation the next time around + finally: + #print time.strftime('%X %x %Z') + pass + + if signedtxn["complete"]: + try: + txid = node.sendrawtransaction(signedtxn["hex"],True) # In the unit tests, we'll just allow high fees + return (txn,inp,outp,txid) + except JSONRPCException as e: + tmp = e.error["message"] + (code, msg) = tmp.split(":") + if int(code) == 64: raise # bad transaction + if int(code) == 258: # txn-mempool-conflict + # we are reusing inputs so this is all the splitting we can do + return (txn,inp,outp,txid) + # print tmp + if e.error["code"] == -26: # insufficient priority + txfeePer = txfeePer * 2 + print(str(e)) + print("Insufficient priority, raising tx fee per byte to: ", txfeePer) + continue + else: + raise + else: + for err in signedtxn["errors"]: + print(err["error"]) + else: + return (txn,inp,outp,txid) + finally: + decimal.getcontext().prec = decContext + +def assert_not_equal(thing1, thing2): + if thing1 == thing2: + raise AssertionError("%s != %s"%(str(thing1),str(thing2))) + +def assert_equal(thing1, thing2): + if thing1 != thing2: + raise AssertionError("%s != %s"%(str(thing1),str(thing2))) + +def assert_greater_than(thing1, thing2): + if thing1 <= thing2: + raise AssertionError("%s <= %s"%(str(thing1),str(thing2))) + +def assert_raises(exc, fun, *args, **kwds): + try: + fun(*args, **kwds) + except exc: + pass + except Exception as e: + raise AssertionError("Unexpected exception raised: "+type(e).__name__) + else: + raise AssertionError("No exception raised") + +def assert_is_hex_string(string): + try: + int(string, 16) + except Exception as e: + raise AssertionError( + "Couldn't interpret %r as hexadecimal; raised: %s" % (string, e)) + +def assert_is_hash_string(string, length=64): + if not isinstance(string, str): + raise AssertionError("Expected a string, got type %r" % type(string)) + elif length and len(string) != length: + raise AssertionError( + "String of length %d expected; got %d" % (length, len(string))) + elif not re.match('[abcdef0-9]+$', string): + raise AssertionError( + "String %r contains invalid characters for a hash." % string) + +def assert_array_result(object_array, to_match, expected, should_not_find = False): + """ + Pass in array of JSON objects, a dictionary with key/value pairs + to match against, and another dictionary with expected key/value + pairs. + If the should_not_find flag is true, to_match should not be found + in object_array + """ + if should_not_find == True: + assert_equal(expected, { }) + num_matched = 0 + for item in object_array: + all_match = True + for key,value in to_match.items(): + if item[key] != value: + all_match = False + if not all_match: + continue + elif should_not_find == True: + num_matched = num_matched+1 + for key,value in expected.items(): + if item[key] != value: + raise AssertionError("%s : expected %s=%s"%(str(item), str(key), str(value))) + num_matched = num_matched+1 + if num_matched == 0 and should_not_find != True: + raise AssertionError("No objects matched %s"%(str(to_match))) + if num_matched > 0 and should_not_find == True: + raise AssertionError("Objects were found %s"%(str(to_match))) + +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() + iterations = count - len(utxos) + addr1 = node.getnewaddress() + addr2 = node.getnewaddress() + if iterations <= 0: + return utxos + for i in range(iterations): + t = utxos.pop() + inputs = [] + inputs.append({ "txid" : t["txid"], "vout" : t["vout"]}) + outputs = {} + send_value = t['amount'] - fee + outputs[addr1] = satoshi_round(send_value/2) + outputs[addr2] = satoshi_round(send_value/2) + raw_tx = node.createrawtransaction(inputs, outputs) + signed_tx = node.signrawtransaction(raw_tx)["hex"] + txid = node.sendrawtransaction(signed_tx) + + while (node.getmempoolinfo()['size'] > 0): + node.generate(1) + + utxos = node.listunspent() + 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) + # create one script_pubkey + script_pubkey = "6a4d0200" #OP_RETURN OP_PUSH2 512 bytes + for i in range (512): + script_pubkey = script_pubkey + "01" + # concatenate 128 txouts of above script_pubkey which we'll insert before the txout for change + txouts = "81" + for k in range(128): + # add txout value + txouts = txouts + "0000000000000000" + # add length of script_pubkey + txouts = txouts + "fd0402" + # add script_pubkey + 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 = [] + for i in range(len(utxos)): + t = utxos.pop() + inputs = [] + inputs.append({ "txid" : t["txid"], "vout" : t["vout"]}) + outputs = {} + send_value = t['amount'] - fee + outputs[addr] = satoshi_round(send_value) + rawtx = node.createrawtransaction(inputs, outputs) + newtx = rawtx[0:92] + newtx = newtx + txouts + newtx = newtx + rawtx[94:] + signresult = node.signrawtransaction(newtx, None, None, "NONE") + txid = node.sendrawtransaction(signresult["hex"], True) + txids.append(txid) + return txids + +def get_bip9_status(node, key): + info = node.getblockchaininfo() + return info['bip9_softforks'][key] diff --git a/qa/rpc-tests/test_template.py b/qa/rpc-tests/test_template.py new file mode 100644 index 00000000..7f645a7b --- /dev/null +++ b/qa/rpc-tests/test_template.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# This is a template to make creating new QA tests easy. +# You can also use this template to quickly start and connect a few regtest nodes. + +import time +import sys +if sys.version_info[0] < 3: + raise "Use Python 3" +import logging +logging.basicConfig(format='%(asctime)s.%(levelname)s: %(message)s', level=logging.INFO,stream=sys.stdout) + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class MyTest (BitcoinTestFramework): + + def setup_chain(self,bitcoinConfDict=None, wallets=None): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4, bitcoinConfDict, wallets) + # Number of nodes to initialize ----------> ^ + + def setup_network(self, split=False): + self.nodes = start_nodes(2, self.options.tmpdir) + # Nodes to start --------^ + # Note for this template I readied 4 nodes but only started 2 + + # Now interconnect the nodes + connect_nodes_bi(self.nodes,0,1) + # Let the framework know if the network is fully connected. + # If not, the framework assumes this partition: (0,1) and (2,3) + # For more complex partitions, you can't use the self.sync* member functions + self.is_network_split=False + self.sync_all() + + def run_test (self): + + logging.info("This is a template for you to use when making new tests") + + # generate enough blocks so that nodes[0] has a balance + self.sync_blocks() + self.nodes[0].generate(101) + self.sync_blocks() + + assert_equal(self.nodes[0].getbalance(), 50) + + # Check that only first and second nodes have UTXOs + assert_equal(len(self.nodes[0].listunspent()), 1) + assert_equal(len(self.nodes[1].listunspent()), 0) + + # Send 1 BTC from 0 to 2 using sendtoaddress call. + try: + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) + except JSONRPCException as e: # an exception you don't catch is a testing error + raise + + # example of stopping and restarting the nodes + stop_nodes(self.nodes) + wait_bitcoinds() + # start 4 nodes this time with some different configuration + self.nodes = start_nodes(4, self.options.tmpdir, [ ["-net.txRetryInterval=5000000"], [], [], []]) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + connect_nodes_bi(self.nodes,2,3) + self.sync_blocks() + + +if __name__ == '__main__': + MyTest ().main () + +# Create a convenient function for an interactive python debugging session +def Test(): + t = MyTest() + bitcoinConf = { + "debug": ["net", "blk", "thin", "mempool", "req", "bench", "evict"], + "blockprioritysize": 2000000 # we don't want any transactions rejected due to insufficient fees... + } + + # you may want these additional flags: + # "--srcdir=/debug/src" + # "--tmpdir=/ramdisk/test" + t.main(["--nocleanup", "--noshutdown"], bitcoinConf, None) diff --git a/qa/rpc-tests/thinblocks.py b/qa/rpc-tests/thinblocks.py new file mode 100644 index 00000000..154c51c0 --- /dev/null +++ b/qa/rpc-tests/thinblocks.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2016 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + + +class ThinBlockTest(BitcoinTestFramework): + def __init__(self): + self.rep = False + BitcoinTestFramework.__init__(self) + + def setup_chain(self): + print ("Initializing test directory " + self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 3) + + def setup_network(self, split=False): + node_opts1 = [ + "-rpcservertimeout=0", + "-debug=thin", + "-use-thinblocks=1", + "-excessiveblocksize=6000000", + "-blockprioritysize=6000000", + "-blockmaxsize=6000000", + "-peerbloomfilters=1"] + + # These options have peerbloomfiters turned off. Xthin's should still work with this option turned off. + node_opts2 = [ + "-rpcservertimeout=0", + "-debug=thin", + "-use-thinblocks=1", + "-excessiveblocksize=6000000", + "-blockprioritysize=6000000", + "-blockmaxsize=6000000", + "-peerbloomfilters=0"] + + self.nodes = [ + start_node(0, self.options.tmpdir, node_opts1), + start_node(1, self.options.tmpdir, node_opts1), + start_node(2, self.options.tmpdir, node_opts2) + ] + interconnect_nodes(self.nodes) + self.is_network_split = False + self.sync_all() + + def run_test(self): + # Generate blocks so we can send a few transactions. We need some transactions in a block + # before an xthin can be send and created, otherwise we'll just end up sending a regular + # block. + self.nodes[0].generate(100) + self.sync_all() + self.nodes[0].generate(5) + self.sync_all() + + # Generate and propagate blocks from a node that has bloomfiltering turned on. + # This should work. + send_to = {} + self.nodes[0].keypoolrefill(20) + for i in range(20): + send_to[self.nodes[1].getnewaddress()] = Decimal("0.01") + self.nodes[0].sendmany("", send_to) + self.sync_all() + + self.nodes[1].generate(1) + self.sync_all() + + # Generate and propagate blocks from a node that does not have bloomfiltering turned on. + # This should work. + send_to = {} + self.nodes[0].keypoolrefill(20) + for i in range(20): + send_to[self.nodes[1].getnewaddress()] = Decimal("0.01") + self.nodes[0].sendmany("", send_to) + self.sync_all() + + self.nodes[2].generate(1) + self.sync_all() + + + # Check thinblock stats + gni = self.nodes[0].getnetworkinfo() + assert "thinblockstats" in gni + + tbs = gni["thinblockstats"] + assert "enabled" in tbs and tbs["enabled"] + + assert set(tbs) == {"enabled", + "summary", + "mempool_limiter", + "inbound_percent", + "outbound_percent", + "response_time", + "validation_time", + "outbound_bloom_filters", + "inbound_bloom_filters", + "rerequested"} + + +if __name__ == '__main__': + ThinBlockTest().main() diff --git a/qa/rpc-tests/txPerf.py b/qa/rpc-tests/txPerf.py new file mode 100644 index 00000000..2f118793 --- /dev/null +++ b/qa/rpc-tests/txPerf.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test re-org scenarios with a mempool that contains transactions +# that spend (directly or indirectly) coinbase transactions. +# +import pdb +import binascii +import time +import math +import json +import logging +logging.basicConfig(format='%(asctime)s.%(levelname)s: %(message)s', level=logging.INFO) + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + + +# Create one-input, one-output, no-fee transaction: +class TransactionPerformanceTest(BitcoinTestFramework): + + def setup_chain(self,bitcoinConfDict=None, wallets=None): + logging.info("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 3, bitcoinConfDict, wallets) + + def setup_network(self, split=False): + self.nodes = start_nodes(3, self.options.tmpdir,timewait=60*60) + + #connect to a local machine for debugging + #url = "http://bitcoinrpc:DP6DvqZtqXarpeNWyN3LZTFchCCyCUuHwNF7E8pX99x1@%s:%d" % ('127.0.0.1', 18332) + #proxy = AuthServiceProxy(url) + #proxy.url = url # store URL on proxy for info + #self.nodes.append(proxy) + + # Connect each node to the other + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + + self.is_network_split=False + self.sync_all() + + def generate_utxos(self,node, count,amt=0.1): + if type(node) == type(0): # Convert a node index to a node object + node = self.nodes[node] + + addrs = [] + for i in range(0,count): + addr = node.getnewaddress() + addrs.append(addr) + node.sendtoaddress(addr, amt) + node.generate(1) + self.sync_all() + + def signingPerformance(self,node, inputs,outputs,skip=100): + fil = open("signPerf.csv","w") + logging.info("tx len, # inputs, # outputs, time") + print ("fieldNames = ['tx len', '# inputs', '# outputs', 'time']", file=fil) + print ("data = [", file=fil) + for i in range(0,len(inputs),skip): + for j in range(0,len(outputs),skip): + try: + if i==0: i=1 + if j==0: j=1 + (txn,inp,outp,txid) = split_transaction(node, inputs[0:i], outputs[0:j], txfee=DEFAULT_TX_FEE_PER_BYTE*10, sendtx=False) + except e: + logging.info("%d, %d, %d, split error" % (txLen,len(inp),len(outp))) + print("[",txLen,",",len(inp),",",len(outp),",",'"split error:"', str(e),'"],', file=fil) + continue + try: + s = str(txn) + #print ("tx len: ", len(s)) + start=time.time() + signedtxn = node.signrawtransaction(s) + end=time.time() + txLen = len(binascii.unhexlify(signedtxn["hex"])) # Get the actual transaction size for better tx fee estimation the next time around + logging.info("%d, %d, %d, %f" % (txLen,len(inp),len(outp),end-start)) + print("[",txLen,",",len(inp),",",len(outp),",",end-start,"],",file=fil) + except: + logging.info("%d, %d, %d, %s" % (txLen,len(inp),len(outp),'"timeout"')) + print (txLen,",",len(inp),",",len(outp),",","timeout") + print ("[",txLen,",",len(inp),",",len(outp),",",'"timeout"],',file=fil) + fil.flush() + print("]",file=fil) + fil.close() + + def validatePerformance(self,node, inputCount,outputs,skip=100): + fil = open("validatePerf.csv","w") + print("tx len, # inputs, # outputs, time") + print ("fieldNames = ['tx len', '# inputs', '# outputs', 'time']",file=fil) + print ("data = [",file=fil) + for i in range(0,inputCount,skip): + for j in range(0,len(outputs),skip): + print("ITER: ", i, " x ", j) + wallet = node.listunspent() + wallet.sort(key=lambda x: x["amount"],reverse=True) + while len(wallet) < i: # Make a bunch more inputs + (txn,inp,outp,txid) = split_transaction(node, [wallet[0]], outputs, txfee=DEFAULT_TX_FEE_PER_BYTE*10) + self.sync_all() + wallet = node.listunspent() + wallet.sort(key=lambda x: x["amount"],reverse=True) + + try: + if i==0: i=1 + if j==0: j=1 + (txn,inp,outp,txid) = split_transaction(node, wallet[0:i], outputs[0:j], txfee=DEFAULT_TX_FEE_PER_BYTE*10, sendtx=True) + except e: + logging.info("split error: %s" % str(e)) + print("[ 'sign',",0,",",i,",",j,",","'split error:", str(e),"'],",file=fil) + pdb.set_trace() + continue + + time.sleep(4) # give the transaction time to propagate so we generate tx validation data separately from block validation data + startTime = time.time() + node.generate(1) + elapsedTime = time.time() - startTime + logging.info("generate time: %f" % elapsedTime) + txLen = len(binascii.unhexlify(txn)) # Get the actual transaction size for better tx fee estimation the next time around + print("[ 'gen',",txLen,",",len(inp),",",len(outp),",",elapsedTime,"],",file=fil) + + startTime = time.time() + self.sync_all() + elapsedTime = time.time() - startTime + logging.info("Sync time: %f" % elapsedTime) + print("[ 'sync',",txLen,",",len(inp),",",len(outp),",",elapsedTime,"],",file=fil) + + print("]",file=fil) + fil.close() + + + def largeOutput(self): + """This times the validation of 1 to many and many to 1 transactions. Its not needed to be run as a daily unit test""" + print("synchronizing") + self.sync_all() + node = self.nodes[0] + start = time.time() + print("generating addresses") + if 1: + addrs = [ node.getnewaddress() for _ in range(20000)] + f = open("addrs.txt","w") + f.write(str(addrs)) + f.close() + print("['Benchmark', 'generate 20000 addresses', %f]" % (time.time()-start)) + else: + import addrlist + addrs = addrlist.addrlist + + wallet = node.listunspent() + wallet.sort(key=lambda x: x["amount"],reverse=True) + + (txn,inp,outp,txid) = split_transaction(node, wallet[0], addrs[0:10000], txfee=DEFAULT_TX_FEE_PER_BYTE, sendtx=True) + txLen = len(binascii.unhexlify(txn)) # Get the actual transaction size for better tx fee estimation the next time around + print("[ 'gen',",txLen,",",len(inp),",",len(outp), "],") + + startTime = time.time() + node.generate(1) + elapsedTime = time.time() - startTime + print ("Generate time: ", elapsedTime) + startTime = time.time() + print ("synchronizing") + self.sync_all() + elapsedTime = time.time() - startTime + print("Sync time: ", elapsedTime) + + # Now join with a tx with a huge number of inputs + wallet = self.nodes[0].listunspent() + wallet.sort(key=lambda x: x["amount"]) + + (txn,inp,outp,txid) = split_transaction(node, wallet[0:10000], [addrs[0]], txfee=DEFAULT_TX_FEE_PER_BYTE, sendtx=True) + txLen = len(binascii.unhexlify(txn)) # Get the actual transaction size for better tx fee estimation the next time around + print("[ 'gen',",txLen,",",len(inp),",",len(outp), "],") + + + + def run_test(self): + TEST_SIZE=200 # To collect a lot of data points, set the TEST_SIZE to 2000 + + #prepare some coins for multiple *rawtransaction commands + self.nodes[2].generate(1) + self.sync_all() + self.nodes[0].generate(100) + self.sync_all() + self.nodes[2].generate(21) # So we can access 10 txouts from nodes[0] + self.sync_all() + + # This times the validation of 1 to many and many to 1 transactions. Its not needed to be run as a unit test + # self.largeOutput() + + print("Generating new addresses... will take awhile") + start = time.time() + addrs = [ self.nodes[0].getnewaddress() for _ in range(TEST_SIZE+1)] + print("['Benchmark', 'generate 2001 addresses', %f]" % (time.time()-start)) + + wallet = self.nodes[0].listunspent() + wallet.sort(key=lambda x: x["amount"],reverse=True) + + for w in wallet[0:2]: + split_transaction(self.nodes[0], [w], addrs) + self.nodes[0].generate(1) + self.sync_all() + #tips = self.nodes[0].getchaintips() + #print ("TIPS:\n", tips) + #lastBlock = self.nodes[0].getblock(tips[0]["hash"]) + #print ("LAST BLOCK:\n", lastBlock) + #txoutsetinfo = self.nodes[0].gettxoutsetinfo() + #print ("UTXOS:\n", txoutsetinfo) + + self.nodes[0].generate(1) + self.sync_all() + + wallet = self.nodes[0].listunspent() + wallet.sort(key=lambda x: x["amount"],reverse=True) + + logging.info("wallet length: %d" % len(wallet)) + logging.info("addrs length: %d" % len(addrs)) + + # To collect a lot of data points, set the interval to 100 or even 10 and run overnight + interval = 100 # TEST_SIZE/2 + + # self.signingPerformance(self.nodes[0], wallet[0:TEST_SIZE],addrs[0:TEST_SIZE],interval) + self.validatePerformance(self.nodes[0], TEST_SIZE,addrs,interval) + + +if __name__ == '__main__': + tpt = TransactionPerformanceTest() + bitcoinConf = { + "debug":["net","blk","thin","lck","mempool","req","bench","evict"], + "blockprioritysize":2000000 # we don't want any transactions rejected due to insufficient fees... + } + tpt.main(["--nocleanup"],bitcoinConf) + +def Test(): + tpt = TransactionPerformanceTest() + bitcoinConf = { + "debug":["bench"], + "blockprioritysize":2000000 # we don't want any transactions rejected due to insufficient fees... + } + tpt.main(["--nocleanup","--tmpdir=/ramdisk/test"],bitcoinConf) + + diff --git a/qa/rpc-tests/txn_clone.py b/qa/rpc-tests/txn_clone.py new file mode 100644 index 00000000..e4e941fd --- /dev/null +++ b/qa/rpc-tests/txn_clone.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test proper accounting with an equivalent malleability clone +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import pdb +import traceback + +class TxnMallTest(BitcoinTestFramework): + + def add_options(self, parser): + parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true", + help="Test double-spend of 1-confirmed transaction") + + def setup_network(self): + # Start with split network: + return super(TxnMallTest, self).setup_network(True) + + def run_test(self): + # All nodes should start with 1,250 BTC: + starting_balance = 1250 + for i in range(4): + assert_equal(self.nodes[i].getbalance(), starting_balance) + self.nodes[i].getnewaddress("") # bug workaround, coins generated assigned to first getnewaddress! + + # Assign coins to foo and bar accounts: + self.nodes[0].settxfee(.001) + + node0_address_foo = self.nodes[0].getnewaddress("foo") + fund_foo_txid = self.nodes[0].sendfrom("", node0_address_foo, 1219) + fund_foo_tx = self.nodes[0].gettransaction(fund_foo_txid) + + node0_address_bar = self.nodes[0].getnewaddress("bar") + fund_bar_txid = self.nodes[0].sendfrom("", node0_address_bar, 29) + fund_bar_tx = self.nodes[0].gettransaction(fund_bar_txid) + + assert_equal(self.nodes[0].getbalance(""), + starting_balance - 1219 - 29 + fund_foo_tx["fee"] + fund_bar_tx["fee"]) + + # Coins are sent to node1_address + node1_address = self.nodes[1].getnewaddress("from0") + + # Send tx1, and another transaction tx2 that won't be cloned + txid1 = self.nodes[0].sendfrom("foo", node1_address, 40, 0) + txid2 = self.nodes[0].sendfrom("bar", node1_address, 20, 0) + + # Construct a clone of tx1, to be malleated + rawtx1 = self.nodes[0].getrawtransaction(txid1,1) + clone_inputs = [{"txid":rawtx1["vin"][0]["txid"],"vout":rawtx1["vin"][0]["vout"]}] + clone_outputs = {rawtx1["vout"][0]["scriptPubKey"]["addresses"][0]:rawtx1["vout"][0]["value"], + rawtx1["vout"][1]["scriptPubKey"]["addresses"][0]:rawtx1["vout"][1]["value"]} + clone_raw = self.nodes[0].createrawtransaction(clone_inputs, clone_outputs) + + # 3 hex manipulations on the clone are required + + # manipulation 1. sequence is at version+#inputs+input+sigstub + posseq = 2*(4+1+36+1) + seqbe = '%08x' % rawtx1["vin"][0]["sequence"] + clone_raw = clone_raw[:posseq] + seqbe[6:8] + seqbe[4:6] + seqbe[2:4] + seqbe[0:2] + clone_raw[posseq + 8:] + + # manipulation 2. createrawtransaction randomizes the order of its outputs, so swap them if necessary. + # output 0 is at version+#inputs+input+sigstub+sequence+#outputs + # 40 BTC serialized is 00286bee00000000 + pos0 = 2*(4+1+36+1+4+1) + hex40 = "00286bee00000000" + output_len = 16 + 2 + 2 * int("0x" + clone_raw[pos0 + 16 : pos0 + 16 + 2], 0) + if (rawtx1["vout"][0]["value"] == 40 and clone_raw[pos0 : pos0 + 16] != hex40 or + rawtx1["vout"][0]["value"] != 40 and clone_raw[pos0 : pos0 + 16] == hex40): + output0 = clone_raw[pos0 : pos0 + output_len] + output1 = clone_raw[pos0 + output_len : pos0 + 2 * output_len] + clone_raw = clone_raw[:pos0] + output1 + output0 + clone_raw[pos0 + 2 * output_len:] + + # manipulation 3. locktime is after outputs + poslt = pos0 + 2 * output_len + ltbe = '%08x' % rawtx1["locktime"] + clone_raw = clone_raw[:poslt] + ltbe[6:8] + ltbe[4:6] + ltbe[2:4] + ltbe[0:2] + clone_raw[poslt + 8:] + + # Use a different signature hash type to sign. This creates an equivalent but malleated clone. + # Don't send the clone anywhere yet + tx1_clone = self.nodes[0].signrawtransaction(clone_raw, None, None, "ALL|ANYONECANPAY") + assert_equal(tx1_clone["complete"], True) + + # Have node0 mine a block, if requested: + if (self.options.mine_block): + self.nodes[0].generate(1) + sync_blocks(self.nodes[0:2]) + + tx1 = self.nodes[0].gettransaction(txid1) + tx2 = self.nodes[0].gettransaction(txid2) + + # Node0's balance should be starting balance, plus 50BTC for another + # matured block, minus tx1 and tx2 amounts, and minus transaction fees: + expected = starting_balance + fund_foo_tx["fee"] + fund_bar_tx["fee"] + if self.options.mine_block: expected += 50 + expected += tx1["amount"] + tx1["fee"] + expected += tx2["amount"] + tx2["fee"] + assert_equal(self.nodes[0].getbalance(), expected) + + # foo and bar accounts should be debited: + assert_equal(self.nodes[0].getbalance("foo", 0), 1219 + tx1["amount"] + tx1["fee"]) + assert_equal(self.nodes[0].getbalance("bar", 0), 29 + tx2["amount"] + tx2["fee"]) + + if self.options.mine_block: + assert_equal(tx1["confirmations"], 1) + assert_equal(tx2["confirmations"], 1) + # Node1's "from0" balance should be both transaction amounts: + assert_equal(self.nodes[1].getbalance("from0"), -(tx1["amount"] + tx2["amount"])) + else: + assert_equal(tx1["confirmations"], 0) + assert_equal(tx2["confirmations"], 0) + + # Send clone and its parent to miner + self.nodes[2].sendrawtransaction(fund_foo_tx["hex"]) + txid1_clone = self.nodes[2].sendrawtransaction(tx1_clone["hex"]) + # ... mine a block... + self.nodes[2].generate(1) + + # Reconnect the split network, and sync chain: + connect_nodes(self.nodes[1], 2) + self.nodes[2].sendrawtransaction(fund_bar_tx["hex"]) + self.nodes[2].sendrawtransaction(tx2["hex"]) + self.nodes[2].generate(1) # Mine another block to make sure we sync + sync_blocks(self.nodes) + + # Re-fetch transaction info: + tx1 = self.nodes[0].gettransaction(txid1) + tx1_clone = self.nodes[0].gettransaction(txid1_clone) + tx2 = self.nodes[0].gettransaction(txid2) + + # Verify expected confirmations + assert_equal(tx1["confirmations"], -2) + assert_equal(tx1_clone["confirmations"], 2) + assert_equal(tx2["confirmations"], 1) + + # Check node0's total balance; should be same as before the clone, + 100 BTC for 2 matured, + # less possible orphaned matured subsidy + expected += 100 + if (self.options.mine_block): + expected -= 50 + assert_equal(self.nodes[0].getbalance(), expected) + assert_equal(self.nodes[0].getbalance("*", 0), expected) + + # Check node0's individual account balances. + # "foo" should have been debited by the equivalent clone of tx1 + assert_equal(self.nodes[0].getbalance("foo"), 1219 + tx1["amount"] + tx1["fee"]) + # "bar" should have been debited by (possibly unconfirmed) tx2 + assert_equal(self.nodes[0].getbalance("bar", 0), 29 + tx2["amount"] + tx2["fee"]) + # "" should have starting balance, less funding txes, plus subsidies + assert_equal(self.nodes[0].getbalance("", 0), starting_balance + - 1219 + + fund_foo_tx["fee"] + - 29 + + fund_bar_tx["fee"] + + 100) + + # Node1's "from0" account balance + assert_equal(self.nodes[1].getbalance("from0", 0), -(tx1["amount"] + tx2["amount"])) + +if __name__ == '__main__': + TxnMallTest().main() + +def Test(): + t = TxnMallTest() + t.drop_to_pdb = True + bitcoinConf = { + "debug": ["net", "blk", "thin", "mempool", "req", "bench", "evict"], # "lck" + "blockprioritysize": 2000000 # we don't want any transactions rejected due to insufficient fees... + } + t.main(["--tmpdir=/ramdisk/test","--nocleanup","--noshutdown"], bitcoinConf, None) # , "--tracerpc"]) diff --git a/qa/rpc-tests/txn_doublespend.py b/qa/rpc-tests/txn_doublespend.py new file mode 100644 index 00000000..067666c4 --- /dev/null +++ b/qa/rpc-tests/txn_doublespend.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test proper accounting with a double-spend conflict +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class TxnMallTest(BitcoinTestFramework): + + def add_options(self, parser): + parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true", + help="Test double-spend of 1-confirmed transaction") + + def setup_network(self): + # Start with split network: + return super(TxnMallTest, self).setup_network(True) + + def run_test(self): + # All nodes should start with 1,250 BTC: + starting_balance = 1250 + for i in range(4): + assert_equal(self.nodes[i].getbalance(), starting_balance) + self.nodes[i].getnewaddress("") # bug workaround, coins generated assigned to first getnewaddress! + + # Assign coins to foo and bar accounts: + node0_address_foo = self.nodes[0].getnewaddress("foo") + fund_foo_txid = self.nodes[0].sendfrom("", node0_address_foo, 1219) + fund_foo_tx = self.nodes[0].gettransaction(fund_foo_txid) + + node0_address_bar = self.nodes[0].getnewaddress("bar") + fund_bar_txid = self.nodes[0].sendfrom("", node0_address_bar, 29) + fund_bar_tx = self.nodes[0].gettransaction(fund_bar_txid) + + assert_equal(self.nodes[0].getbalance(""), + starting_balance - 1219 - 29 + fund_foo_tx["fee"] + fund_bar_tx["fee"]) + + # Coins are sent to node1_address + node1_address = self.nodes[1].getnewaddress("from0") + + # First: use raw transaction API to send 1240 BTC to node1_address, + # but don't broadcast: + doublespend_fee = Decimal('-.02') + rawtx_input_0 = {} + rawtx_input_0["txid"] = fund_foo_txid + rawtx_input_0["vout"] = find_output(self.nodes[0], fund_foo_txid, 1219) + rawtx_input_1 = {} + rawtx_input_1["txid"] = fund_bar_txid + rawtx_input_1["vout"] = find_output(self.nodes[0], fund_bar_txid, 29) + inputs = [rawtx_input_0, rawtx_input_1] + change_address = self.nodes[0].getnewaddress() + outputs = {} + outputs[node1_address] = 1240 + outputs[change_address] = 1248 - 1240 + doublespend_fee + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + doublespend = self.nodes[0].signrawtransaction(rawtx) + assert_equal(doublespend["complete"], True) + + # Create two spends using 1 50 BTC coin each + txid1 = self.nodes[0].sendfrom("foo", node1_address, 40, 0) + txid2 = self.nodes[0].sendfrom("bar", node1_address, 20, 0) + + # Have node0 mine a block: + if (self.options.mine_block): + self.nodes[0].generate(1) + sync_blocks(self.nodes[0:2]) + + tx1 = self.nodes[0].gettransaction(txid1) + tx2 = self.nodes[0].gettransaction(txid2) + + # Node0's balance should be starting balance, plus 50BTC for another + # matured block, minus 40, minus 20, and minus transaction fees: + expected = starting_balance + fund_foo_tx["fee"] + fund_bar_tx["fee"] + if self.options.mine_block: expected += 50 + expected += tx1["amount"] + tx1["fee"] + expected += tx2["amount"] + tx2["fee"] + assert_equal(self.nodes[0].getbalance(), expected) + + # foo and bar accounts should be debited: + assert_equal(self.nodes[0].getbalance("foo", 0), 1219+tx1["amount"]+tx1["fee"]) + assert_equal(self.nodes[0].getbalance("bar", 0), 29+tx2["amount"]+tx2["fee"]) + + if self.options.mine_block: + assert_equal(tx1["confirmations"], 1) + assert_equal(tx2["confirmations"], 1) + # Node1's "from0" balance should be both transaction amounts: + assert_equal(self.nodes[1].getbalance("from0"), -(tx1["amount"]+tx2["amount"])) + else: + assert_equal(tx1["confirmations"], 0) + assert_equal(tx2["confirmations"], 0) + + # Now give doublespend and its parents to miner: + self.nodes[2].sendrawtransaction(fund_foo_tx["hex"]) + self.nodes[2].sendrawtransaction(fund_bar_tx["hex"]) + doublespend_txid = self.nodes[2].sendrawtransaction(doublespend["hex"]) + # ... mine a block... + self.nodes[2].generate(1) + + # Reconnect the split network, and sync chain: + connect_nodes(self.nodes[1], 2) + self.nodes[2].generate(1) # Mine another block to make sure we sync + sync_blocks(self.nodes) + assert_equal(self.nodes[0].gettransaction(doublespend_txid)["confirmations"], 2) + + # Re-fetch transaction info: + tx1 = self.nodes[0].gettransaction(txid1) + tx2 = self.nodes[0].gettransaction(txid2) + + # Both transactions should be conflicted + assert_equal(tx1["confirmations"], -2) + assert_equal(tx2["confirmations"], -2) + + # Node0's total balance should be starting balance, plus 100BTC for + # two more matured blocks, minus 1240 for the double-spend, plus fees (which are + # negative): + expected = starting_balance + 100 - 1240 + fund_foo_tx["fee"] + fund_bar_tx["fee"] + doublespend_fee + assert_equal(self.nodes[0].getbalance(), expected) + assert_equal(self.nodes[0].getbalance("*"), expected) + + # Final "" balance is starting_balance - amount moved to accounts - doublespend + subsidies + + # fees (which are negative) + assert_equal(self.nodes[0].getbalance("foo"), 1219) + assert_equal(self.nodes[0].getbalance("bar"), 29) + assert_equal(self.nodes[0].getbalance(""), starting_balance + -1219 + - 29 + -1240 + + 100 + + fund_foo_tx["fee"] + + fund_bar_tx["fee"] + + doublespend_fee) + + # Node1's "from0" account balance should be just the doublespend: + assert_equal(self.nodes[1].getbalance("from0"), 1240) + +if __name__ == '__main__': + TxnMallTest().main() + diff --git a/qa/rpc-tests/validateblocktemplate.py b/qa/rpc-tests/validateblocktemplate.py new file mode 100644 index 00000000..b2e46f7f --- /dev/null +++ b/qa/rpc-tests/validateblocktemplate.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import pdb +import sys +if sys.version_info[0] < 3: + raise "Use Python 3" +import logging +logging.basicConfig(format='%(asctime)s.%(levelname)s: %(message)s', level=logging.INFO, stream=sys.stdout) + +# Test validateblocktemplate RPC call +from test_framework.key import CECKey +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.script import * +from test_framework.mininode import * +from test_framework.blocktools import * + +# Create a transaction with an anyone-can-spend output, that spends the +# nth output of prevtx. pass a single integer value to make one output, +# or a list to create multiple outputs + + +def create_broken_transaction(prevtx, n, sig, value): + if not type(value) is list: + value = [value] + tx = CTransaction() + tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), sig, 0xffffffff)) + for v in value: + tx.vout.append(CTxOut(v, b"")) + tx.calc_sha256() + return tx + + +def expectException(fn, ExcType, comparison=None): + try: + fn() + except ExcType as exc: + if comparison: + if comparison in str(exc): # exception matchs + return + else: + print("Incorrect error. Was: " + str(exc) + " Expecting: " + comparison) + assert(0) + else: + return + assert(0) # an exception should have happened + + +class ValidateblocktemplateTest(BitcoinTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug"])) + self.is_network_split = False + connect_nodes(self.nodes[0], 1) + + def run_test(self): + # Generate enough blocks to trigger certain block votes + self.nodes[0].generate(1001) + + logging.info("not on chain tip") + badtip = int(self.nodes[0].getblockhash(self.nodes[0].getblockcount() - 1), 16) + height = self.nodes[0].getblockcount() + tip = int(self.nodes[0].getblockhash(height), 16) + + coinbase = create_coinbase(height + 1) + cur_time = int(time.time()) + self.nodes[0].setmocktime(cur_time) + self.nodes[1].setmocktime(cur_time) + + block = create_block(badtip, coinbase, cur_time + 600) + block.nVersion = 0x20000000 + block.rehash() + + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: does not build on chain tip") + + logging.info("time too far in the past") + block = create_block(tip, coinbase, cur_time) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate( + hexblk), JSONRPCException, "invalid block: time-too-old") + + logging.info("time too far in the future") + block = create_block(tip, coinbase, cur_time + 10000000) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate( + hexblk), JSONRPCException, "invalid block: time-too-new") + + logging.info("bad version 1") + block = create_block(tip, coinbase, cur_time + 600) + block.nVersion = 1 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate( + hexblk), JSONRPCException, "invalid block: bad-version") + logging.info("bad version 2") + block = create_block(tip, coinbase, cur_time + 600) + block.nVersion = 2 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate( + hexblk), JSONRPCException, "invalid block: bad-version") + logging.info("bad version 3") + block = create_block(tip, coinbase, cur_time + 600) + block.nVersion = 3 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate( + hexblk), JSONRPCException, "invalid block: bad-version") + + logging.info("bad coinbase height") + tip = int(self.nodes[0].getblockhash(height), 16) + block = create_block(tip, create_coinbase(height - 10), cur_time + 600) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate( + hexblk), JSONRPCException, "invalid block: bad-cb-height") + + logging.info("bad merkle root") + block = create_block(tip, coinbase, cur_time + 600) + block.nVersion = 0x20000000 + block.hashMerkleRoot = 0x12345678 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: bad-txnmrklroot") + + logging.info("no tx") + block = create_block(tip, None, cur_time + 600) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: bad-blk-length") + + logging.info("good block") + block = create_block(tip, coinbase, cur_time + 600) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + + # ------ + self.nodes[0].validateblocktemplate(hexblk) + block.solve() + hexblk = ToHex(block) + self.nodes[0].submitblock(hexblk) + self.sync_all() + + prev_block = block + # out_value is less than 50BTC because regtest halvings happen every 150 blocks, and is in Satoshis + out_value = block.vtx[0].vout[0].nValue + tx1 = create_transaction(prev_block.vtx[0], 0, b'\x51', [int(out_value / 2), int(out_value / 2)]) + height = self.nodes[0].getblockcount() + tip = int(self.nodes[0].getblockhash(height), 16) + coinbase = create_coinbase(height + 1) + next_time = cur_time + 1200 + + logging.info("no coinbase") + block = create_block(tip, None, next_time, [tx1]) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: bad-cb-missing") + + logging.info("double coinbase") + + coinbase_key = CECKey() + coinbase_key.set_secretbytes(b"horsebattery") + coinbase_pubkey = coinbase_key.get_pubkey() + + coinbase2 = create_coinbase(height + 1, coinbase_pubkey) + block = create_block(tip, coinbase, next_time, [coinbase2, tx1]) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: bad-cb-multiple") + + logging.info("premature coinbase spend") + block = create_block(tip, coinbase, next_time, [tx1]) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: bad-txns-premature-spend-of-coinbase") + + self.nodes[0].generate(100) + self.sync_all() + height = self.nodes[0].getblockcount() + tip = int(self.nodes[0].getblockhash(height), 16) + coinbase = create_coinbase(height + 1) + next_time = cur_time + 1200 + + logging.info("inputs below outputs") + tx6 = create_transaction(prev_block.vtx[0], 0, b'\x51', [out_value + 1000]) + block = create_block(tip, coinbase, next_time, [tx6]) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: bad-txns-in-belowout") + + tx5 = create_transaction(prev_block.vtx[0], 0, b'\x51', [int(21000001 * COIN)]) + logging.info("money range") + block = create_block(tip, coinbase, next_time, [tx5]) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: bad-txns-vout-toolarge") + + logging.info("bad tx offset") + tx_bad = create_broken_transaction(prev_block.vtx[0], 1, b'\x51', [int(out_value / 4)]) + block = create_block(tip, coinbase, next_time, [tx_bad]) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: bad-txns-inputs-missingorspent") + + logging.info("bad tx offset largest number") + tx_bad = create_broken_transaction(prev_block.vtx[0], 0xffffffff, b'\x51', [int(out_value / 4)]) + block = create_block(tip, coinbase, next_time, [tx_bad]) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: bad-txns-inputs-missingorspent") + + logging.info("double tx") + tx2 = create_transaction(prev_block.vtx[0], 0, b'\x51', [int(out_value / 4)]) + block = create_block(tip, coinbase, next_time, [tx2, tx2]) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: bad-txns-inputs-missingorspent") + + tx3 = create_transaction(prev_block.vtx[0], 0, b'\x51', [int(out_value / 9), int(out_value / 10)]) + tx4 = create_transaction(prev_block.vtx[0], 0, b'\x51', [int(out_value / 8), int(out_value / 7)]) + logging.info("double spend") + block = create_block(tip, coinbase, next_time, [tx3, tx4]) + block.nVersion = 0x20000000 + block.rehash() + hexblk = ToHex(block) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: bad-txns-inputs-missingorspent") + + tx_good = create_transaction(prev_block.vtx[0], 0, b'\x51', [int(out_value / 50)] * 50) + logging.info("good tx") + block = create_block(tip, coinbase, next_time, [tx_good]) + block.nVersion = 0x20000000 + block.rehash() + block.solve() + hexblk = ToHex(block) + self.nodes[0].validateblocktemplate(hexblk) + self.nodes[0].submitblock(hexblk) + + self.sync_all() + + height = self.nodes[0].getblockcount() + tip = int(self.nodes[0].getblockhash(height), 16) + coinbase = create_coinbase(height + 1) + next_time = next_time + 600 + + coinbase_key = CECKey() + coinbase_key.set_secretbytes(b"horsebattery") + coinbase_pubkey = coinbase_key.get_pubkey() + coinbase3 = create_coinbase(height + 1, coinbase_pubkey) + + txl = [] + for i in range(0, 50): + ov = block.vtx[1].vout[i].nValue + txl.append(create_transaction(block.vtx[1], i, b'\x51', [int(ov / 50)] * 50)) + block = create_block(tip, coinbase, next_time, txl) + block.nVersion = 0x20000000 + block.rehash() + block.solve() + hexblk = ToHex(block) + for n in self.nodes: + n.validateblocktemplate(hexblk) + + logging.info("excessive") + self.nodes[0].setminingmaxblock(1000) + self.nodes[0].setexcessiveblock(1000, 12) + expectException(lambda: self.nodes[0].validateblocktemplate(hexblk), + JSONRPCException, "invalid block: excessive") + self.nodes[0].setexcessiveblock(16 * 1000 * 1000, 12) + self.nodes[0].setminingmaxblock(1000 * 1000) + + for it in range(0, 100): + # if (it&1023)==0: print(it) + h2 = hexblk + pos = random.randint(0, len(hexblk)) + val = random.randint(0, 15) + h3 = h2[:pos] + ('%x' % val) + h2[pos + 1:] + try: + self.nodes[0].validateblocktemplate(h3) + except JSONRPCException as e: + if not (e.error["code"] == -1 or e.error["code"] == -22): + print(str(e)) + # its ok we expect garbage + + self.nodes[1].submitblock(hexblk) + self.sync_all() + + height = self.nodes[0].getblockcount() + tip = int(self.nodes[0].getblockhash(height), 16) + coinbase = create_coinbase(height + 1) + next_time = next_time + 600 + prev_block = block + txl = [] + for tx in prev_block.vtx: + for outp in range(0, len(tx.vout)): + ov = tx.vout[outp].nValue + txl.append(create_transaction(tx, outp, CScript([OP_CHECKSIG] * 100), [int(ov / 2)] * 2)) + block = create_block(tip, coinbase, next_time, txl) + block.nVersion = 0x20000000 + block.rehash() + block.solve() + hexblk = ToHex(block) + for n in self.nodes: + expectException(lambda: n.validateblocktemplate(hexblk), JSONRPCException, + "invalid block: bad-blk-sigops") + + +def Test(): + try: + t = ValidateblocktemplateTest() + bitcoinConf = { + "debug": ["net", "blk", "thin", "mempool", "req", "bench", "evict"], # "lck" + "blockprioritysize": 2000000 # we don't want any transactions rejected due to insufficient fees... + } +# t.main(["--tmpdir=/ramdisk/test", "--nocleanup", "--noshutdown"], bitcoinConf, None) + t.main(["--tmpdir=/ramdisk/test","--nocleanup", "--noshutdown"], bitcoinConf, None) + except Exception as e: + print(str(e)) + pdb.pm() + + +if __name__ == '__main__': + bitcoinConf = { + "debug": ["net", "blk", "thin", "mempool", "req", "bench", "evict"] + } + ValidateblocktemplateTest().main([],bitcoinConf) diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py new file mode 100644 index 00000000..9efa8d58 --- /dev/null +++ b/qa/rpc-tests/wallet.py @@ -0,0 +1,375 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +import time +import sys +if sys.version_info[0] < 3: + raise "Use Python 3" +import logging +logging.basicConfig(format='%(asctime)s.%(levelname)s: %(message)s', level=logging.INFO,stream=sys.stdout) + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class WalletTest (BitcoinTestFramework): + + def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size): + """Return curr_balance after asserting the fee was in range""" + fee = balance_with_fee - curr_balance + target_fee = fee_per_byte * tx_size + if fee < target_fee: + raise AssertionError("Fee of %s BTC too low! (Should be %s BTC)"%(str(fee), str(target_fee))) + # allow the node's estimation to be at most 2 bytes off + if fee > fee_per_byte * (tx_size + 2): + raise AssertionError("Fee of %s BTC too high! (Should be %s BTC)"%(str(fee), str(target_fee))) + return curr_balance + + def setup_chain(self,bitcoinConfDict=None, wallets=None): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4, bitcoinConfDict, wallets) + + def setup_network(self, split=False): + self.nodes = start_nodes(3, self.options.tmpdir) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + self.is_network_split=False + self.sync_all() + + def run_test (self): + + # Check that there's no UTXO on none of the nodes + assert_equal(len(self.nodes[0].listunspent()), 0) + assert_equal(len(self.nodes[1].listunspent()), 0) + assert_equal(len(self.nodes[2].listunspent()), 0) + + print("Mining blocks...") + + self.nodes[0].generate(1) + + walletinfo = self.nodes[0].getwalletinfo() + assert_equal(walletinfo['immature_balance'], 50) + assert_equal(walletinfo['balance'], 0) + + self.sync_all() + self.nodes[1].generate(101) + self.sync_all() + + assert_equal(self.nodes[0].getbalance(), 50) + assert_equal(self.nodes[1].getbalance(), 50) + assert_equal(self.nodes[2].getbalance(), 0) + + # Check that only first and second nodes have UTXOs + assert_equal(len(self.nodes[0].listunspent()), 1) + assert_equal(len(self.nodes[1].listunspent()), 1) + assert_equal(len(self.nodes[2].listunspent()), 0) + + # Send 21 BTC from 0 to 2 using sendtoaddress call. + # Second transaction will be child of first, and will require a fee + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) + + walletinfo = self.nodes[0].getwalletinfo() + assert_equal(walletinfo['immature_balance'], 0) + + # Have node0 mine a block, thus it will collect its own fee. + 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() + + # node0 should end up with 100 btc in block rewards plus fees, but + # minus the 21 plus fees sent to node2 + assert_equal(self.nodes[0].getbalance(), 100-21) + assert_equal(self.nodes[2].getbalance(), 21) + + # Node0 should have two unspent outputs. + # Create a couple of transactions to send them to node2, submit them through + # node1, and make sure both node0 and node2 pick them up properly: + node0utxos = self.nodes[0].listunspent(1) + assert_equal(len(node0utxos), 2) + + # create both transactions + txns_to_send = [] + for utxo in node0utxos: + inputs = [] + outputs = {} + inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]}) + outputs[self.nodes[2].getnewaddress("from1")] = utxo["amount"] + raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) + txns_to_send.append(self.nodes[0].signrawtransaction(raw_tx)) + + # Have node 1 (miner) send the transactions + self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], True) + self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True) + + # Have node1 mine a block to confirm transactions: + self.nodes[1].generate(1) + self.sync_all() + + assert_equal(self.nodes[0].getbalance(), 0) + assert_equal(self.nodes[2].getbalance(), 100) + assert_equal(self.nodes[2].getbalance("from1"), 100-21) + + # Send 10 BTC normal + address = self.nodes[0].getnewaddress("test") + fee_per_byte = Decimal('0.001') / 1000 + self.nodes[2].settxfee(fee_per_byte * 1000) + txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) + self.nodes[2].generate(1) + self.sync_all() + node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('90'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) + assert_equal(self.nodes[0].getbalance(), Decimal('10')) + + # Send 10 BTC with subtract fee from amount + txid = self.nodes[2].sendtoaddress(address, 10, "", "", True) + self.nodes[2].generate(1) + self.sync_all() + node_2_bal -= Decimal('10') + assert_equal(self.nodes[2].getbalance(), node_2_bal) + node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) + + # Sendmany 10 BTC + txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", []) + self.nodes[2].generate(1) + self.sync_all() + node_0_bal += Decimal('10') + node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) + assert_equal(self.nodes[0].getbalance(), node_0_bal) + + # Sendmany 10 BTC with subtract fee from amountd + txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", [address]) + self.nodes[2].generate(1) + self.sync_all() + node_2_bal -= Decimal('10') + assert_equal(self.nodes[2].getbalance(), node_2_bal) + node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) + + # Test ResendWalletTransactions: + # Create a couple of transactions, then start up a fourth + # node (nodes[3]) and ask nodes[0] to rebroadcast. + # EXPECT: nodes[3] should have those transactions in its mempool. + txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) + txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) + sync_mempools(self.nodes) + + self.nodes.append(start_node(3, self.options.tmpdir)) + connect_nodes_bi(self.nodes, 0, 3) + sync_blocks(self.nodes) + + relayed = self.nodes[0].resendwallettransactions() + assert_equal(set(relayed), {txid1, txid2}) + sync_mempools(self.nodes) + + 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 + #3. sign and send + #4. check if recipient (node0) can list the zero value tx + usp = self.nodes[1].listunspent() + inputs = [{"txid":usp[0]['txid'], "vout":usp[0]['vout']}] + outputs = {self.nodes[1].getnewaddress(): 49.998, self.nodes[0].getnewaddress(): 11.11} + + rawTx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") #replace 11.11 with 0.0 (int32) + decRawTx = self.nodes[1].decoderawtransaction(rawTx) + signedRawTx = self.nodes[1].signrawtransaction(rawTx) + decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex']) + zeroValueTxid= decRawTx['txid'] + sendResp = self.nodes[1].sendrawtransaction(signedRawTx['hex']) + + self.sync_all() + self.nodes[1].generate(1) #mine a block + self.sync_all() + + unspentTxs = self.nodes[0].listunspent() #zero value tx must be in listunspents output + found = False + for uTx in unspentTxs: + if uTx['txid'] == zeroValueTxid: + found = True + assert_equal(uTx['amount'], Decimal('0')) + assert(found) + + #do some -walletbroadcast tests + stop_nodes(self.nodes) + wait_bitcoinds() + self.nodes = start_nodes(3, self.options.tmpdir, [["-walletbroadcast=0"],["-walletbroadcast=0"],["-walletbroadcast=0"]]) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + self.sync_all() + + txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) + txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) + self.nodes[1].generate(1) #mine a block, tx should not be in there + self.sync_all() + assert_equal(self.nodes[2].getbalance(), node_2_bal) #should not be changed because tx was not broadcasted + + #now broadcast from another node, mine a block, sync, and check the balance + self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex']) + self.nodes[1].generate(1) + self.sync_all() + node_2_bal += 2 + txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) + assert_equal(self.nodes[2].getbalance(), node_2_bal) + + #create another tx + txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) + + #restart the nodes with -walletbroadcast=1 + stop_nodes(self.nodes) + wait_bitcoinds() + self.nodes = start_nodes(3, self.options.tmpdir) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + sync_blocks(self.nodes) + + self.nodes[0].generate(1) + sync_blocks(self.nodes) + node_2_bal += 2 + + #tx should be added to balance because after restarting the nodes tx should be broadcastet + assert_equal(self.nodes[2].getbalance(), node_2_bal) + + #send a tx with value in a string (PR#6380 +) + txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2") + txObj = self.nodes[0].gettransaction(txId) + assert_equal(txObj['amount'], Decimal('-2')) + + txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001") + txObj = self.nodes[0].gettransaction(txId) + assert_equal(txObj['amount'], Decimal('-0.0001')) + + #check if JSON parser can handle scientific notation in strings + txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1e-4") + txObj = self.nodes[0].gettransaction(txId) + assert_equal(txObj['amount'], Decimal('-0.0001')) + + try: + txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1f-4") + except JSONRPCException as e: + assert("Invalid amount" in e.error['message']) + else: + raise AssertionError("Must not parse invalid amounts") + + + try: + self.nodes[0].generate("2") + raise AssertionError("Must not accept strings as numeric") + except JSONRPCException as e: + assert("not an integer" in e.error['message']) + + # Import address and private key to check correct behavior of spendable unspents + # 1. Send some coins to generate new UTXO + address_to_import = self.nodes[2].getnewaddress() + txid = self.nodes[0].sendtoaddress(address_to_import, 1) + self.nodes[0].generate(1) + self.sync_all() + + # 2. Import address from node2 to node1 + self.nodes[1].importaddress(address_to_import) + + # 3. Validate that the imported address is watch-only on node1 + assert(self.nodes[1].validateaddress(address_to_import)["iswatchonly"]) + + # 4. Check that the unspents after import are not spendable + assert_array_result(self.nodes[1].listunspent(), + {"address": address_to_import}, + {"spendable": False}) + + # 5. Import private key of the previously imported address on node1 + priv_key = self.nodes[2].dumpprivkey(address_to_import) + self.nodes[1].importprivkey(priv_key) + + # 6. Check that the unspents are now spendable on node1 + assert_array_result(self.nodes[1].listunspent(), + {"address": address_to_import}, + {"spendable": True}) + + # 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 as 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() + blocks = self.nodes[0].generate(2) + self.sync_all() + balance_nodes = [self.nodes[i].getbalance() for i in range(3)] + block_count = self.nodes[0].getblockcount() + + # Check modes: + # - True: unicode escaped as \u.... + # - False: unicode directly as UTF-8 + for mode in [True, False]: + self.nodes[0].ensure_ascii = mode + # unicode check: Basic Multilingual Plane, Supplementary Plane respectively + for s in [u'рыба', u'𝅘𝅥𝅯']: + addr = self.nodes[0].getaccountaddress(s) + label = self.nodes[0].getaccount(addr) + assert_equal(label, s) + assert(s in self.nodes[0].listaccounts().keys()) + self.nodes[0].ensure_ascii = True # restore to default + + # maintenance tests + maintenance = [ + '-rescan', + '-reindex', + '-zapwallettxes=1', + '-zapwallettxes=2', + '-salvagewallet', + ] + for m in maintenance: + print("check " + m) + stop_nodes(self.nodes) + wait_bitcoinds() + self.nodes = start_nodes(3, self.options.tmpdir, [[m]] * 3) + while m == '-reindex' and [block_count] * 3 != [self.nodes[i].getblockcount() for i in range(3)]: + # reindex will leave rpc warm up "early"; Wait for it to finish + time.sleep(0.1) + 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 () + +def Test(): + t = WalletTest() + bitcoinConf = { + "debug": ["net", "blk", "thin", "mempool", "req", "bench", "evict"], # "lck" + "blockprioritysize": 2000000 # we don't want any transactions rejected due to insufficient fees... + } + # "--tmpdir=/ramdisk/test", + t.main(["--nocleanup", "--noshutdown"], bitcoinConf, None) diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py new file mode 100644 index 00000000..c62d3db1 --- /dev/null +++ b/qa/rpc-tests/walletbackup.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +""" +Exercise the wallet backup code. Ported from walletbackup.sh. + +Test case is: +4 nodes. 1 2 and 3 send transactions between each other, +fourth node is a miner. +1 2 3 each mine a block to start, then +Miner creates 100 blocks so 1 2 3 each have 50 mature +coins to spend. +Then 5 iterations of 1/2/3 sending coins amongst +themselves to get transactions in the wallets, +and the miner mining one block. + +Wallets are backed up using dumpwallet/backupwallet. +Then 5 more iterations of transactions and mining a block. + +Miner then generates 101 more blocks, so any +transaction fees paid mature. + +Sanity check: + Sum(1,2,3,4 balances) == 114*50 + +1/2/3 are shutdown, and their wallets erased. +Then restore using wallet.dat backup. And +confirm 1/2/3/4 balances are same as before. + +Shutdown again, restore using importwallet, +and confirm again balances are correct. +""" +import pdb + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from random import randint +import logging +logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO, stream=sys.stdout) + +class WalletBackupTest(BitcoinTestFramework): + + def setup_chain(self): + logging.info("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + # This mirrors how the network was setup in the bash test + def setup_network(self, split=False): + # nodes 1, 2,3 are spenders, let's give them a keypool=100 + extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []] + self.nodes = start_nodes(4, self.options.tmpdir, extra_args) + connect_nodes(self.nodes[0], 3) + connect_nodes(self.nodes[1], 3) + connect_nodes(self.nodes[2], 3) + connect_nodes(self.nodes[2], 0) + self.is_network_split=False + self.sync_all() + + def one_send(self, from_node, to_address): + if (randint(1,2) == 1): + amount = Decimal(randint(1,10)) / Decimal(10) + self.nodes[from_node].sendtoaddress(to_address, amount) + + def do_one_round(self): + a0 = self.nodes[0].getnewaddress() + a1 = self.nodes[1].getnewaddress() + a2 = self.nodes[2].getnewaddress() + + self.one_send(0, a1) + self.one_send(0, a2) + self.one_send(1, a0) + self.one_send(1, a2) + self.one_send(2, a0) + self.one_send(2, a1) + + # Have the miner (node3) mine a block. + # Must sync mempools before mining. + sync_mempools(self.nodes) + self.nodes[3].generate(1) + + # As above, this mirrors the original bash test. + def start_three(self): + self.nodes[0] = start_node(0, self.options.tmpdir) + self.nodes[1] = start_node(1, self.options.tmpdir) + self.nodes[2] = start_node(2, self.options.tmpdir) + connect_nodes(self.nodes[0], 3) + connect_nodes(self.nodes[1], 3) + connect_nodes(self.nodes[2], 3) + connect_nodes(self.nodes[2], 0) + + def stop_three(self): + stop_node(self.nodes[0], 0) + stop_node(self.nodes[1], 1) + stop_node(self.nodes[2], 2) + + def erase_three(self): + os.remove(self.options.tmpdir + "/node0/regtest/wallet.dat") + os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat") + os.remove(self.options.tmpdir + "/node2/regtest/wallet.dat") + + def run_test(self): + logging.info("Generating initial blockchain") + self.nodes[0].generate(1) + sync_blocks(self.nodes) + self.nodes[1].generate(1) + sync_blocks(self.nodes) + self.nodes[2].generate(1) + sync_blocks(self.nodes) + self.nodes[3].generate(100) + sync_blocks(self.nodes) + + assert_equal(self.nodes[0].getbalance(), 50) + assert_equal(self.nodes[1].getbalance(), 50) + assert_equal(self.nodes[2].getbalance(), 50) + assert_equal(self.nodes[3].getbalance(), 0) + + logging.info("Creating transactions") + # Five rounds of sending each other transactions. + for i in range(5): + self.do_one_round() + + logging.info("Backing up") + tmpdir = self.options.tmpdir + self.nodes[0].backupwallet(tmpdir + "/node0/wallet.bak") + self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.dump") + self.nodes[1].backupwallet(tmpdir + "/node1/wallet.bak") + self.nodes[1].dumpwallet(tmpdir + "/node1/wallet.dump") + self.nodes[2].backupwallet(tmpdir + "/node2/wallet.bak") + self.nodes[2].dumpwallet(tmpdir + "/node2/wallet.dump") + + logging.info("More transactions") + for i in range(5): + self.do_one_round() + + # Generate 101 more blocks, so any fees paid mature + self.nodes[3].generate(101) + self.sync_all() + + balance0 = self.nodes[0].getbalance() + balance1 = self.nodes[1].getbalance() + balance2 = self.nodes[2].getbalance() + balance3 = self.nodes[3].getbalance() + total = balance0 + balance1 + balance2 + balance3 + + # At this point, there are 214 blocks (103 for setup, then 10 rounds, then 101.) + # 114 are mature, so the sum of all wallets should be 114 * 50 = 5700. + assert_equal(total, 5700) + + ## + # Test restoring spender wallets from backups + ## + logging.info("Restoring using wallet.dat") + self.stop_three() + self.erase_three() + + # Start node2 with no chain + shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks") + shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate") + + # Restore wallets from backup + shutil.copyfile(tmpdir + "/node0/wallet.bak", tmpdir + "/node0/regtest/wallet.dat") + shutil.copyfile(tmpdir + "/node1/wallet.bak", tmpdir + "/node1/regtest/wallet.dat") + shutil.copyfile(tmpdir + "/node2/wallet.bak", tmpdir + "/node2/regtest/wallet.dat") + + logging.info("Re-starting nodes") + self.start_three() + sync_blocks(self.nodes) + + assert_equal(self.nodes[0].getbalance(), balance0) + assert_equal(self.nodes[1].getbalance(), balance1) + assert_equal(self.nodes[2].getbalance(), balance2) + + logging.info("Restoring using dumped wallet") + self.stop_three() + self.erase_three() + + #start node2 with no chain + shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks") + shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate") + + self.start_three() + + assert_equal(self.nodes[0].getbalance(), 0) + assert_equal(self.nodes[1].getbalance(), 0) + assert_equal(self.nodes[2].getbalance(), 0) + + self.nodes[0].importwallet(tmpdir + "/node0/wallet.dump") + self.nodes[1].importwallet(tmpdir + "/node1/wallet.dump") + self.nodes[2].importwallet(tmpdir + "/node2/wallet.dump") + + sync_blocks(self.nodes) + + assert_equal(self.nodes[0].getbalance(), balance0) + assert_equal(self.nodes[1].getbalance(), balance1) + assert_equal(self.nodes[2].getbalance(), balance2) + + +if __name__ == '__main__': + WalletBackupTest().main() diff --git a/qa/rpc-tests/zapwallettxes.py b/qa/rpc-tests/zapwallettxes.py new file mode 100644 index 00000000..832994f8 --- /dev/null +++ b/qa/rpc-tests/zapwallettxes.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + + +class ZapWalletTXesTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 3) + + def setup_network(self, split=False): + self.nodes = start_nodes(3, self.options.tmpdir) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + self.is_network_split=False + self.sync_all() + + def run_test (self): + print("Mining blocks...") + self.nodes[0].generate(1) + self.sync_all() + self.nodes[1].generate(101) + self.sync_all() + + assert_equal(self.nodes[0].getbalance(), 50) + + txid0 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) + txid1 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + txid2 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) + txid3 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) + + tx0 = self.nodes[0].gettransaction(txid0) + assert_equal(tx0['txid'], txid0) #tx0 must be available (confirmed) + + tx1 = self.nodes[0].gettransaction(txid1) + assert_equal(tx1['txid'], txid1) #tx1 must be available (confirmed) + + tx2 = self.nodes[0].gettransaction(txid2) + assert_equal(tx2['txid'], txid2) #tx2 must be available (unconfirmed) + + tx3 = self.nodes[0].gettransaction(txid3) + assert_equal(tx3['txid'], txid3) #tx3 must be available (unconfirmed) + + #restart bitcoind + self.nodes[0].stop() + bitcoind_processes[0].wait() + self.nodes[0] = start_node(0,self.options.tmpdir) + + tx3 = self.nodes[0].gettransaction(txid3) + assert_equal(tx3['txid'], txid3) #tx must be available (unconfirmed) + + self.nodes[0].stop() + bitcoind_processes[0].wait() + + #restart bitcoind with zapwallettxes + self.nodes[0] = start_node(0,self.options.tmpdir, ["-zapwallettxes=1"]) + + 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 + + +if __name__ == '__main__': + ZapWalletTXesTest ().main () diff --git a/qa/rpc-tests/zmq_test.py b/qa/rpc-tests/zmq_test.py new file mode 100644 index 00000000..4058ee54 --- /dev/null +++ b/qa/rpc-tests/zmq_test.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test ZMQ interface +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import zmq +import struct + +import http.client +import urllib.parse + +class ZMQTest (BitcoinTestFramework): + + port = 28332 + + def setup_nodes(self): + self.zmqContext = zmq.Context() + self.zmqSubSocket = self.zmqContext.socket(zmq.SUB) + self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock") + self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx") + self.zmqSubSocket.linger = 500 + self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % self.port) + return start_nodes(4, self.options.tmpdir, extra_args=[ + ['-zmqpubhashtx=tcp://127.0.0.1:'+str(self.port), '-zmqpubhashblock=tcp://127.0.0.1:'+str(self.port)], + [], + [], + [] + ]) + + def run_test(self): + try: + self.sync_all() + + genhashes = self.nodes[0].generate(1) + self.sync_all() + + print("listen...") + msg = self.zmqSubSocket.recv_multipart() + topic = msg[0] + body = msg[1] + + msg = self.zmqSubSocket.recv_multipart() + topic = msg[0] + body = msg[1] + blkhash = bytes_to_hex_str(body) + + assert_equal(genhashes[0], blkhash) #blockhash from generate must be equal to the hash received over zmq + + n = 10 + genhashes = self.nodes[1].generate(n) + self.sync_all() + + zmqHashes = [] + for x in range(0,n*2): + msg = self.zmqSubSocket.recv_multipart() + topic = msg[0] + body = msg[1] + if topic == b"hashblock": + zmqHashes.append(bytes_to_hex_str(body)) + + for x in range(0,n): + assert_equal(genhashes[x], zmqHashes[x]) #blockhash from generate must be equal to the hash received over zmq + + #test tx from a second node + hashRPC = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.0) + self.sync_all() + + # now we should receive a zmq msg because the tx was broadcast + msg = self.zmqSubSocket.recv_multipart() + topic = msg[0] + body = msg[1] + hashZMQ = "" + if topic == b"hashtx": + hashZMQ = bytes_to_hex_str(body) + + assert_equal(hashRPC, hashZMQ) #blockhash from generate must be equal to the hash received over zmq + finally: + self.zmqSubSocket.close() + self.zmqSubSocket = None + self.zmqContext.destroy() + self.zmqContext = None + + +if __name__ == '__main__': + ZMQTest ().main () + +def Test(): + ZMQTest ().main () + diff --git a/share/certs/BitcoinFoundation_Apple_Cert.pem b/share/certs/BitcoinFoundation_Apple_Cert.pem new file mode 100644 index 00000000..beb0d707 --- /dev/null +++ b/share/certs/BitcoinFoundation_Apple_Cert.pem @@ -0,0 +1,37 @@ +Bag Attributes + friendlyName: Developer ID Application: BITCOIN FOUNDATION, INC., THE + localKeyID: 6B 9C 6C A8 A5 73 70 70 E2 57 A3 49 D8 62 FB 97 C7 A5 5D 5E +subject=/UID=PBV4GLS9J4/CN=Developer ID Application: BITCOIN FOUNDATION, INC., THE/OU=PBV4GLS9J4/O=BITCOIN FOUNDATION, INC., THE/C=US +issuer=/CN=Developer ID Certification Authority/OU=Apple Certification Authority/O=Apple Inc./C=US +-----BEGIN CERTIFICATE----- +MIIFhzCCBG+gAwIBAgIIJ0r1rumyfZAwDQYJKoZIhvcNAQELBQAweTEtMCsGA1UE +AwwkRGV2ZWxvcGVyIElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQL +DB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUg +SW5jLjELMAkGA1UEBhMCVVMwHhcNMTMwMTEwMjIzOTAxWhcNMTgwMTExMjIzOTAx +WjCBqDEaMBgGCgmSJomT8ixkAQEMClBCVjRHTFM5SjQxQDA+BgNVBAMMN0RldmVs +b3BlciBJRCBBcHBsaWNhdGlvbjogQklUQ09JTiBGT1VOREFUSU9OLCBJTkMuLCBU +SEUxEzARBgNVBAsMClBCVjRHTFM5SjQxJjAkBgNVBAoMHUJJVENPSU4gRk9VTkRB +VElPTiwgSU5DLiwgVEhFMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALTd5zURuZVoJviusr119aktXksenb9IN9vq6kBbq38vxEk7 +9wkKMES2XfBRh0HxcEizGzhMNy5OCXuTLMaNMihYdfwYSoBoR2foEU+6kjPUnyJ4 +dQBFLJZJr5/QeQmALmYHEgZ6lwXFD2lU8t92340zeJ4y5LZw5pcEHtH9IummYDut +OGCkCGXDcjL+5nHhNScJiXHhswM+62o6XXsQiP6EWbM1CsgrGTNLtaa0U/UvVDwE +79YKklSC5Bog2LD0jBcTuveI66mFzqu++L9X9u+ZArtebwCl7BPNQ+uboYy5uV2d +zf8lpNNZLfXCFjoLe9bLICKfZ7ub9V5aC8+GhckCAwEAAaOCAeEwggHdMD4GCCsG +AQUFBwEBBDIwMDAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuYXBwbGUuY29tL29j +c3AtZGV2aWQwMTAdBgNVHQ4EFgQUa5xsqKVzcHDiV6NJ2GL7l8elXV4wDAYDVR0T +AQH/BAIwADAfBgNVHSMEGDAWgBRXF+2iz9x8mKEQ4Py+hy0s8uMXVDCCAQ4GA1Ud +IASCAQUwggEBMIH+BgkqhkiG92NkBQEwgfAwKAYIKwYBBQUHAgEWHGh0dHA6Ly93 +d3cuYXBwbGUuY29tL2FwcGxlY2EwgcMGCCsGAQUFBwICMIG2DIGzUmVsaWFuY2Ug +b24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2NlcHRh +bmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNv +bmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRpZmlj +YXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wDgYDVR0PAQH/BAQDAgeAMBYGA1Ud +JQEB/wQMMAoGCCsGAQUFBwMDMBMGCiqGSIb3Y2QGAQ0BAf8EAgUAMA0GCSqGSIb3 +DQEBCwUAA4IBAQAfJ0BjID/1dS2aEeVyhAzPzCBjG8vm0gDf+/qfwRn3+yWeL9vS +nMdbilwM48IyQWTagjGGcojbsAd/vE4N7NhQyHInoCllNoeor1I5xx+blTaGRBK+ +dDhJbbdlGCjsLnH/BczGZi5fyEJds9lUIrp1hJidRcUKO76qb/9gc6qNZpl1vH5k +lDUuJYt7YhAs+L6rTXDyqcK9maeQr0gaOPsRRAQLLwiQCorPeMTUNsbVMdMwZYJs +R+PxiAnk+nyi7rfiFvPoASAYUuI6OzYL/Fa6QU4/gYyPgic944QYVkaQBnc0vEP1 +nXq6LGKwgVGcqJnkr/E2kui5gJoV5C3qll3e +-----END CERTIFICATE----- diff --git a/share/certs/BitcoinFoundation_Comodo_Cert.pem b/share/certs/BitcoinFoundation_Comodo_Cert.pem new file mode 100644 index 00000000..dc752d45 --- /dev/null +++ b/share/certs/BitcoinFoundation_Comodo_Cert.pem @@ -0,0 +1,37 @@ +Bag Attributes + friendlyName: The Bitcoin Foundation, Inc.'s COMODO CA Limited ID + localKeyID: 8C 94 64 E3 B5 B0 41 89 5B 89 B0 57 CC 74 B9 44 E5 B2 92 66 +subject=/C=US/postalCode=98104-1444/ST=WA/L=Seattle/street=Suite 300/street=71 Columbia St/O=The Bitcoin Foundation, Inc./CN=The Bitcoin Foundation, Inc. +issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Code Signing CA 2 +-----BEGIN CERTIFICATE----- +MIIFeDCCBGCgAwIBAgIRAJVYMd+waOER7lUqtiz3M2IwDQYJKoZIhvcNAQEFBQAw +ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxITAfBgNV +BAMTGENPTU9ETyBDb2RlIFNpZ25pbmcgQ0EgMjAeFw0xMzAxMTYwMDAwMDBaFw0x +NDAxMTYyMzU5NTlaMIG8MQswCQYDVQQGEwJVUzETMBEGA1UEEQwKOTgxMDQtMTQ0 +NDELMAkGA1UECAwCV0ExEDAOBgNVBAcMB1NlYXR0bGUxEjAQBgNVBAkMCVN1aXRl +IDMwMDEXMBUGA1UECQwONzEgQ29sdW1iaWEgU3QxJTAjBgNVBAoMHFRoZSBCaXRj +b2luIEZvdW5kYXRpb24sIEluYy4xJTAjBgNVBAMMHFRoZSBCaXRjb2luIEZvdW5k +YXRpb24sIEluYy4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChUwLD +u/hu5aFZ/n11B27awONaaDrmHm0pamiWHb01yL4JmTBtaLCrSftF8RhCscQ8jpI0 +UG1Cchmay0e3zH5o5XRs0H9C3x+SM5ozms0TWDmAYiB8aQEghsGovDk0D2nyTQeK +Q0xqyCh0m8ZPOnMnYrakHEmF6WvhLdJvI6Od4KIwbKxgN17cPFIfLVsZ7GrzmmbU +Gdi4wSQCHy5rxzvBxho8Qq/SfBl93uOMUrqOHjOUAPhNuTJG3t/MdhU8Zp24s29M +abHtYkT9W86hMjIiI8RTAR+WHKVglx9SB0cjDabXN8SZ3gME0+H++LyzlySHT8sI +ykepojZ7UBRgp9w3AgMBAAGjggGzMIIBrzAfBgNVHSMEGDAWgBQexbEsfYfaAmh8 +JbwMB4Q/ts/e8TAdBgNVHQ4EFgQUfPf+ZyDWl/4LH0Y5BuJTelkRd/EwDgYDVR0P +AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYJ +YIZIAYb4QgEBBAQDAgQQMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQMCMCswKQYI +KwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5uZXQvQ1BTMEEGA1UdHwQ6 +MDgwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET0NvZGVTaWdu +aW5nQ0EyLmNybDByBggrBgEFBQcBAQRmMGQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9j +cnQuY29tb2RvY2EuY29tL0NPTU9ET0NvZGVTaWduaW5nQ0EyLmNydDAkBggrBgEF +BQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMCgGA1UdEQQhMB+BHWxpbmRz +YXlAYml0Y29pbmZvdW5kYXRpb24ub3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAqibjo +D4HG5XSIIMCmYE5RgQBSEAJfI+EZERk1G9F83ZUWr0yNRZCw4O+RaM7xQhvJhEoD +G2kpk/q2bNOc71/VyZ6SrE1JRVUON41/Flhz4M6cP0BclTicXvh+efVwqZhIz+ws +UxF2hvC/1Xx6rqI7NYAlOYXk2MSUq3HREo+gWUPKM8em4MZZV/7XCH4QbsfxOl1J +xS6EOQmV8hfUN4KRXI5WfGUmedBxq7dM0RSJOSQl8fq2f+JjRLfjQwQucy7LDY+y +pRTsL2TdQV/DuDuI3s0NHRGznQNddoX5jqpXhSQFAAdgrhN1gGkWaaTPzr9IF2TG +qgr6PEp9tIYC+MbM +-----END CERTIFICATE----- diff --git a/share/certs/PrivateKeyNotes.md b/share/certs/PrivateKeyNotes.md new file mode 100644 index 00000000..da299d16 --- /dev/null +++ b/share/certs/PrivateKeyNotes.md @@ -0,0 +1,46 @@ +Code-signing private key notes +== + +The private keys for these certificates were generated on Gavin's main work machine, +following the certificate authoritys' recommendations for generating certificate +signing requests. + +For OSX, the private key was generated by Keychain.app on Gavin's main work machine. +The key and certificate is in a separate, passphrase-protected keychain file that is +unlocked to sign the Bitcoin-Qt.app bundle. + +For Windows, the private key was generated by Firefox running on Gavin's main work machine. +The key and certificate were exported into a separate, passphrase-protected PKCS#12 file, and +then deleted from Firefox's keystore. The exported file is used to sign the Windows setup.exe. + +Threat analysis +-- + +Gavin is a single point of failure. He could be coerced to divulge the secret signing keys, +allowing somebody to distribute a Bitcoin-Qt.app or bitcoin-qt-setup.exe with a valid +signature but containing a malicious binary. + +Or the machine Gavin uses to sign the binaries could be compromised, either remotely or +by breaking in to his office, allowing the attacker to get the private key files and then +install a keylogger to get the passphrase that protects them. + +Threat Mitigation +-- + +"Air gapping" the machine used to do the signing will not work, because the signing +process needs to access a timestamp server over the network. And it would not +prevent the "rubber hose cryptography" threat (coercing Gavin to sign a bad binary +or divulge the private keys). + +Windows binaries are reproducibly 'gitian-built', and the setup.exe file created +by the NSIS installer system is a 7zip archive, so you could check to make sure +that the bitcoin-qt.exe file inside the installer had not been tampered with. +However, an attacker could modify the installer's code, so when the setup.exe +was run it compromised users' systems. A volunteer to write an auditing tool +that checks the setup.exe for tampering, and checks the files in it against +the list of gitian signatures, is needed. + +The long-term solution is something like the 'gitian downloader' system, which +uses signatures from multiple developers to determine whether or not a binary +should be trusted. However, that just pushes the problem to "how will +non-technical users securely get the gitian downloader code to start?" diff --git a/share/genbuild.sh b/share/genbuild.sh old mode 100644 new mode 100755 index d959877d..a15cb34e --- a/share/genbuild.sh +++ b/share/genbuild.sh @@ -1,5 +1,7 @@ #!/bin/sh - +if [ $# -gt 1 ]; then + cd "$2" +fi if [ $# -gt 0 ]; then FILE="$1" shift @@ -7,23 +9,35 @@ if [ $# -gt 0 ]; then INFO="$(head -n 1 "$FILE")" fi else - echo "Usage: $0 " + echo "Usage: $0 " exit 1 fi -if [ -e "$(which git)" ]; then +DESC="" +SUFFIX="" +LAST_COMMIT_DATE="" +if [ -e "$(which git 2>/dev/null)" -a "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]; then # clean 'dirty' status of touched files that haven't been modified git diff >/dev/null 2>/dev/null - # get a string like "v0.6.0-66-g59887e8-dirty" - DESC="$(git describe --dirty 2>/dev/null)" + # if latest commit is tagged and not dirty, then override using the tag name + RAWDESC=$(git describe --abbrev=0 2>/dev/null) + if [ "$(git rev-parse HEAD)" = "$(git rev-list -1 $RAWDESC 2>/dev/null)" ]; then + git diff-index --quiet HEAD -- && DESC=$RAWDESC + fi + + # otherwise generate suffix from git, i.e. string like "59887e8-dirty" + SUFFIX=$(git rev-parse --short HEAD) + git diff-index --quiet HEAD -- || SUFFIX="$SUFFIX-dirty" # get a string like "2012-04-10 16:27:19 +0200" - TIME="$(git log -n 1 --format="%ci")" + LAST_COMMIT_DATE="$(git log -n 1 --format="%ci")" fi if [ -n "$DESC" ]; then NEWINFO="#define BUILD_DESC \"$DESC\"" +elif [ -n "$SUFFIX" ]; then + NEWINFO="#define BUILD_SUFFIX $SUFFIX" else NEWINFO="// No build information available" fi @@ -31,5 +45,7 @@ fi # only update build.h if necessary if [ "$INFO" != "$NEWINFO" ]; then echo "$NEWINFO" >"$FILE" - echo "#define BUILD_DATE \"$TIME\"" >>"$FILE" + if [ -n "$LAST_COMMIT_DATE" ]; then + echo "#define BUILD_DATE \"$LAST_COMMIT_DATE\"" >> "$FILE" + fi fi diff --git a/share/pixmaps/addressbook16.bmp b/share/pixmaps/addressbook16.bmp deleted file mode 100644 index c5576910..00000000 Binary files a/share/pixmaps/addressbook16.bmp and /dev/null differ diff --git a/share/pixmaps/addressbook16mask.bmp b/share/pixmaps/addressbook16mask.bmp deleted file mode 100644 index d3a478d1..00000000 Binary files a/share/pixmaps/addressbook16mask.bmp and /dev/null differ diff --git a/share/pixmaps/addressbook20.bmp b/share/pixmaps/addressbook20.bmp deleted file mode 100644 index 2b33b228..00000000 Binary files a/share/pixmaps/addressbook20.bmp and /dev/null differ diff --git a/share/pixmaps/addressbook20mask.bmp b/share/pixmaps/addressbook20mask.bmp deleted file mode 100644 index 56ce6125..00000000 Binary files a/share/pixmaps/addressbook20mask.bmp and /dev/null differ diff --git a/share/pixmaps/bitcoin-bc.ico b/share/pixmaps/bitcoin-bc.ico deleted file mode 100644 index 88cc240e..00000000 Binary files a/share/pixmaps/bitcoin-bc.ico and /dev/null differ diff --git a/share/pixmaps/bitcoin.ico b/share/pixmaps/bitcoin.ico index 61926807..f5480f41 100644 Binary files a/share/pixmaps/bitcoin.ico and b/share/pixmaps/bitcoin.ico differ diff --git a/share/pixmaps/bitcoin128.png b/share/pixmaps/bitcoin128.png new file mode 100644 index 00000000..b31f4443 Binary files /dev/null and b/share/pixmaps/bitcoin128.png differ diff --git a/share/pixmaps/bitcoin128.xpm b/share/pixmaps/bitcoin128.xpm new file mode 100644 index 00000000..d8e41e9e --- /dev/null +++ b/share/pixmaps/bitcoin128.xpm @@ -0,0 +1,384 @@ +/* XPM */ +static char *bitcoin___[] = { +/* columns rows colors chars-per-pixel */ +"128 128 250 2", +" c #845415", +". c #895616", +"X c #84581E", +"o c #8D5C18", +"O c #925A15", +"+ c #925E1C", +"@ c #98621C", +"# c #9E711C", +"$ c #A36E1A", +"% c #A96F1B", +"& c #A6711C", +"* c #AC741C", +"= c #B2741E", +"- c #B37C1E", +"; c #BB7C1E", +": c #835B21", +"> c #8F6125", +", c #956727", +"< c #916B2E", +"1 c #996B2C", +"2 c #B47B23", +"3 c #BD7C20", +"4 c #A17330", +"5 c #AB7D3B", +"6 c #C17F20", +"7 c #B9831F", +"8 c #BB842B", +"9 c #BD8533", +"0 c #B68F3D", +"q c #BE8C3B", +"w c #C4801F", +"e c #FE8C03", +"r c #F38A0F", +"t c #FD8E0A", +"y c #FF910C", +"u c #F78F13", +"i c #F98F10", +"p c #F79016", +"a c #FE9314", +"s c #F6931E", +"d c #FD961B", +"f c #FE991E", +"g c #C58421", +"h c #CD8621", +"j c #C78B21", +"k c #CC8B23", +"l c #C2852B", +"z c #C08B2D", +"x c #D28722", +"c c #D38B25", +"v c #DB8E22", +"b c #D28E2C", +"n c #D49323", +"m c #DC9224", +"M c #DC9B25", +"N c #D4922D", +"B c #DF972A", +"V c #DF982E", +"C c #C18D33", +"Z c #C58E38", +"A c #CB9332", +"S c #C2933C", +"D c #CD9339", +"F c #CC9938", +"G c #D19733", +"H c #DA9230", +"J c #D59935", +"K c #DC9C33", +"L c #DC9E3B", +"P c #E49124", +"I c #EA9426", +"U c #E09D26", +"Y c #EC972B", +"T c #F79625", +"R c #F99524", +"E c #F69A26", +"W c #F89825", +"Q c #F2972B", +"! c #F59A2C", +"~ c #F89B2B", +"^ c #E79D33", +"/ c #EF9D31", +"( c #E19F3A", +") c #EF9D3A", +"_ c #F49C33", +"` c #F99E32", +"' c #F49F39", +"] c #D6A13E", +"[ c #DAA33B", +"{ c #E3A127", +"} c #E7A328", +"| c #EDA32C", +" . c #EDA829", +".. c #FFA325", +"X. c #FFAB25", +"o. c #F3A42B", +"O. c #FFA429", +"+. c #F4A929", +"@. c #FFAC2A", +"#. c #FFB227", +"$. c #FFB32C", +"%. c #FFBA2D", +"&. c #EEA830", +"*. c #F7A334", +"=. c #FAA036", +"-. c #FCAB34", +";. c #F4A13C", +":. c #F9A33B", +">. c #F4A83B", +",. c #FFA83F", +"<. c #FDB432", +"1. c #FFBB33", +"2. c #FFB73A", +"3. c #FDB93E", +"4. c #FFC12F", +"5. c #FFC432", +"6. c #FFC338", +"7. c #D2A043", +"8. c #D8A140", +"9. c #EEA144", +"0. c #E2A840", +"q. c #EDA34B", +"w. c #F4A444", +"e. c #F9A642", +"r. c #FBA945", +"t. c #F3A64B", +"y. c #F4A84E", +"u. c #FBAB4B", +"i. c #EEB041", +"p. c #FABA44", +"a. c #ECA653", +"s. c #EEAC5D", +"d. c #F3AA53", +"f. c #FAAE53", +"g. c #F2AD5A", +"h. c #FBB056", +"j. c #F6B15E", +"k. c #FBB25B", +"l. c #DDAF79", +"z. c #E3A962", +"x. c #EBAE63", +"c. c #E4AC68", +"v. c #EAAF69", +"b. c #EEB065", +"n. c #E7B06C", +"m. c #EEB36B", +"M. c #F5B263", +"N. c #FBB461", +"B. c #E6B274", +"V. c #ECB574", +"C. c #E7B57B", +"Z. c #EAB77C", +"A. c #ECB97C", +"S. c #F2B770", +"D. c #F0BB7A", +"F. c #DBB485", +"G. c #DFB888", +"H. c #E4B984", +"J. c #EDBD82", +"K. c #E5BC8B", +"L. c #EABE8A", +"P. c #F0BE82", +"I. c #E0BF96", +"U. c #EDC089", +"Y. c #F0C28B", +"T. c #E5C194", +"R. c #E9C191", +"E. c #E4C39C", +"W. c #EBC699", +"Q. c #EBC99F", +"!. c #DFC3A0", +"~. c #DDCAAF", +"^. c #CFC7BD", +"/. c #D2CBB6", +"(. c #DBC8B1", +"). c #DBCDBB", +"_. c #E2C6A4", +"`. c #E6C8A5", +"'. c #EACBA5", +"]. c #E1C7A8", +"[. c #E3CBAD", +"{. c #EACCAA", +"}. c #EED1AC", +"|. c #E1CDB3", +" X c #E3CFB8", +".X c #E6D1B6", +"XX c #EBD2B3", +"oX c #E3D1BB", +"OX c #EAD6BB", +"+X c #EBD8BF", +"@X c #D3CDC2", +"#X c #D8CDC2", +"$X c #D0CECA", +"%X c #DDD3C4", +"&X c #D3D2CC", +"*X c #DDD5CB", +"=X c #CCD3D5", +"-X c #C9D7DF", +";X c #D2D4D6", +":X c #DEDAD4", +">X c #DDDCDB", +",X c #E2D4C2", +".N b b b b N >.( C > HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX4 L _ *.@.<.$.X.X...X.X.X.X.X.X...X.@.$.<.@.*./ G , HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX< L -.@.$.X...R R R T T T T W W W W W W T T T T R R W ..X.$.@.*.J HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXD -.%.X.W R T T W W W W W W W W W W W W W W W W W W W W W W T T R W X.%.+.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXS -.$.X.R T T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T T R X.$.-.C HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXF <.@.f R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T R W #.<.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX[ <.X.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T R X.$.K HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX0.$...R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E W W W W W W W T R ..%.G HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXS 1...R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ E W W W W W W W W W T R X.1.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3.X.d T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ E W W W W W W W W W W T R @.2.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX7.5.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W T W %.z HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3.X.s T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W T R $.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX1...R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E E W W W W W W W W W W W W W R ..1.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX0 5.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W T W 5.8 HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX8.$.s W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W T R %.N HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXi.#.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W R $.&.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXp.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W R @.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXp.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W R @.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXi.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ E ~ W R ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W R @.| HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX] #.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ! s e t d ~ ` ` ` ` ` ` =.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W R %.N HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXq %.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E W E ~ ~ ~ ~ y l.=XI.x.) p a =.` ` =.=.=.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W R %.2 HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX5 5.d W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ t (.jXVXNXuX@XF.W ` =.:.` W =.:.=.=.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T R 5.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX1.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ R Q eXDXSXSXDXgX#Xa ` =.=.;.q.W a a R ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T W %.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3...T W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ` a a.NXSXGXGXAXNXV.a :.:.f c.tX*XE.n.9.R ~ ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W T @.@.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXD #.R W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` t H.VXSXGXGXDXmXy.f :.:.a I.hXBXCXNXiX^.' W ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W R %.g HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX5.d W W W W W W W W W W W W W W W W W W W W W W W W W E ~ W ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` i |.CXGXGXGXCX3X~ ` :.:.R %XCXSXGXAXNX>XW ~ ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W R 5.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX2.W T W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ s t e a W ~ ` ` ` ` ` ` W ! eXFXGXGXSXVX[.d :.:.~ w.uXFXGXGXSXVXW.a ` ` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W T ..@.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX9 $.R W W W W W W W W W W W W W W W W W W W W W W E W ~ ~ ~ y F./.B.9.T t t a ~ =.` =.a a.hXDXGXGXSXNXA.d :.e.R v.NXSXGXGXSXNXm.a =.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W R %.= HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX6.d W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ W i &XjXNXfX:X].B.q.T t a d e K.VXSXGXGXDXaXd.W e.e.d E.VXSXGXGXDXvXw.W =.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W W W %.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXK X.T W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ a ) uXDXSXFXFXCXNXfX:X_.B.q.r .XFXGXGXGXCX3X=.=.e.,.~ %XCXGXGXGXCX1XW ` =.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W T $.m HXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHX5.R W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ t x.NXSXGXGXGXSXSXDXFXCXNXmX8XcXSXGXGXGXCXW.e :.e.=.t.uXFXGXGXSXVXE.d :.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHX^ X.T W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ` t T.VXSXGXGXGXGXGXGXGXSXSXFXGXGXGXGXGXGXFX}.9.' W e v.VXSXGXGXSXNXm.d :.=.=.=.` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W W T @.P HXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHX1.R W W W W W W W W W W W W W W W W E E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ s ;XNXAXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXNX>X|.V.XXFXGXGXGXFXbXy.~ :.:.=.=.` ` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXH X.T W W W W W W W W W W W W W W E E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` R ' $XsXNXVXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXCXCXFXSXGXGXGXCXOXa :.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W T $.c HXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHX1.R W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ~ t.V.`.5XVXFXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFXXFXGXGXGXGXGXGXGXSXCX{.e.P.'.2XvXNXBXDXSXGXGXGXGXGXGXGXGXGXSXDXjX~.y W =.` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W @.HXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHX: 1.R W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.:.e.e.e.~ s.fXDXGXGXGXGXGXGXGXSXNXD.f =.=.,.M.L.oXaXVXDXSXGXGXGXGXGXGXGXGXGXAXVX(.t ~ ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W R %. HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXl #.T W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.:.:.:.:.:.:.:.:.:.e.e.e.e.r.W H.NXSXGXGXGXGXGXGXGXDXzXg.r.f.f.f.r.=.=.g.`.fXBXAXGXGXGXGXGXGXGXGXGXAXjXH.t =.` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T $.6 HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHX~ ..W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.e.e.e.e.e.e.e.r.W |.CXGXGXGXGXGXGXGXGXBX1X,.f.f.f.f.h.h.f.,.~ d.3XVXAXGXGXGXGXGXGXGXGXGXDXsX' f ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W ..~ HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHX$.R W W W W W E ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.=.:.:.:.:.:.:.:.e.e.e.e.e.r.r.r.,.w.>XFXGXGXGXGXGXGXGXSXNX`.=.f.h.h.h.h.f.f.f.f.=.~ ,XVXSXGXGXGXGXGXGXGXGXSXVXT.y ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W R $.HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXX %.T W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.:.e.e.e.e.e.e.r.r.r.u.=.x.fXDXGXGXGXGXGXGXGXSXmXA.,.h.h.h.k.k.h.f.f.f.f.:.~ 5XFXGXGXGXGXGXGXGXGXGXCX:XW ~ ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W T $.. HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHX8 $.T W W W W W W E ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.:.:.:.:.e.e.e.e.e.r.r.r.r.r.u.u.~ K.NXSXGXGXGXGXGXGXGXDXzXj.r.k.k.k.k.k.h.f.f.f.f.f.W V.VXSXGXGXGXGXGXGXGXGXDXuXw.f ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W T $.3 HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXY ..W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.:.e.e.e.e.e.e.r.r.r.r.u.u.u.u.~ |.CXGXGXGXGXGXGXGXGXBX2Xr.f.k.k.k.k.k.k.h.f.f.f.f.,.d.bXFXGXGXGXGXGXGXGXGXDXfXd.d =.` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W O.P HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXO.W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.e.e.e.r.r.r.r.r.r.u.u.u.u.r.w.>XFXGXGXGXGXGXGXGXSXNX'.,.k.k.k.k.k.k.k.h.h.f.f.f.e.y.kXFXGXGXGXGXGXGXGXGXDXfXg.d =.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W O.HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHX$.R W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.=.:.:.:.:.e.e.r.r.r.r.u.u.u.u.u.u.f.=.b.fXDXGXGXGXGXGXGXGXSXmXJ.r.k.k.k.k.k.k.k.h.h.f.f.f.:.s.mXFXGXGXGXGXGXGXGXGXDXpXy.R =.` ` ` ~ ~ ~ ~ ~ E E W W W W W W W W W W W W W W W W W $.HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHX1.R W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.u.u.u.f.=.K.NXSXGXGXGXGXGXGXGXFXxXM.u.k.k.k.k.k.k.k.k.h.f.f.k.~ K.VXSXGXGXGXGXGXGXGXGXCX5X=.~ =.=.` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W $.HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHX+ $.T W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.f.f.f.=.|.CXGXGXGXGXGXGXGXGXFXXFXGXGXGXGXGXGXGXGXFX9XA.b.u.r.r.u.u.h.h.h.u.r.O.w.:XCXSXGXGXGXGXGXGXGXGXSXhXL.a :.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W T $.* HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXV X.T W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.f.,.b.fXFXGXGXGXGXGXGXGXGXSXFXVXpX*X[.R.V.M.g.d.d.g.b.T.pXCXSXGXGXGXGXGXGXGXGXGXDXpXe.~ :.:.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W T $.; HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHX| O.T W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.:.e.e.r.r.u.u.u.u.f.=.K.NXSXGXGXGXGXGXGXGXGXGXGXSXFXFXBXNXmXuX>X3X3XyXmXVXFXSXGXGXGXGXGXGXGXGXGXAXhXE.d :.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W T @.h HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` =.:.:.:.:.:.e.e.e.r.r.u.u.u.u.=.|.BXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXSXSXFXFXFXFXFXSXSXGXGXGXGXGXGXGXGXGXGXAXNX>X~ =.e.:.:.:.=.` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.:.:.:.:.e.e.e.r.r.r.u.u.r.w.>XFXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXZXNXeXe.~ e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.=.x.fXFXGXGXGXGXGXGXGXGXGXFXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFXCXfXoX:.~ r.e.:.:.:.:.:.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.:.e.e.r.r.r.u.~ K.NXSXGXGXGXGXGXGXGXSXZX6XkXmXNXBXDXAXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGX0X'.S.~ =.u.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.e.e.r.r.u.~ |.CXGXGXGXGXGXGXGXGXFX4X,.k.D.Q.,XkXmXNXDXSXSXGXGXGXGXGXGXGXGXGXGXGXXFXGXGXGXGXGXGXGXSXVX{.,.f.u.r.u.N.J.{.5XNXBXAXSXGXGXGXGXGXGXGXGXGXFXMXH.W r.u.r.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W T @.h HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXo.O.T W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.O.s.fXFXGXGXGXGXGXGXGXSXmXJ.r.N.N.N.N.h.r.r.f.J.1XhXBXAXGXGXGXGXGXGXGXGXSXDXjX!.W e.u.r.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W T @.g HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXB X.T W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.:.:.:.:.:.e.e.r.W H.NXSXGXGXGXGXGXGXGXDXuXM.u.k.k.N.N.N.N.N.h.,.e.D.>XNXSXGXGXGXGXGXGXGXGXSXZXjXE.W r.r.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W T $.- HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXl @.T W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.r.W |.CXGXGXGXGXGXGXGXGXBX2Xr.h.k.k.k.k.k.k.k.k.k.h.,.,.|.NXZXGXGXGXGXGXGXGXGXGXZXgXV.~ u.e.e.e.:.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W T $.% HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHX@ $.T W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.:.' >XFXGXGXGXGXGXGXGXSXNX{.,.k.k.k.k.k.k.k.k.k.k.k.k.u.~ `.NXSXGXGXGXGXGXGXGXGXSXCX>X=.e.r.r.e.e.:.:.:.:.:.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W T $.. HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHX%.R W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.~ s.fXFXGXGXGXGXGXGXGXSXNXJ.,.k.k.k.k.k.k.k.k.k.k.h.h.k.u.O.2XCXGXGXGXGXGXGXGXGXGXAXhXV.~ u.r.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W $.HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHX$.R W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` ~ :.:.:.:.e.f Z.VXSXGXGXGXGXGXGXGXDXzXM.r.k.k.k.k.k.k.k.h.h.h.h.f.f.k.=.V.NXSXGXGXGXGXGXGXGXGXSXVX`.W r.e.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W $.HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXO.W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` =.~ Q a a W =.=.t XCXGXGXGXGXGXGXGXGXBX2Xr.f.k.k.k.k.k.k.h.h.h.h.f.f.f.f.r.y.kXFXGXGXGXGXGXGXGXGXGXBX,X~ :.e.e.e.:.:.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W ~ ..HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXI O.W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` a z.-X_.B.q.! u C.NXSXGXGXGXGXGXGXGXSXNX'.=.h.h.k.k.k.h.h.f.f.f.f.f.f.f.f.r.w.5XFXGXGXGXGXGXGXGXGXGXCX2X=.:.e.:.:.:.:.:.:.:.:.=.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W O.P HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ t ).jXVXNXaX2X1XBXDXSXGXGXGXGXGXGXGXSXmXA.:.h.h.h.h.h.f.f.f.f.f.f.f.f.f.f.,.d.vXFXGXGXGXGXGXGXGXGXGXCX1X` =.:.:.:.:.:.:.=.=.=.=.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W T $.; HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXo %.T W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ` y q.fXZXSXSXFXFXFXSXSXGXGXGXGXGXGXGXGXFXxXj.r.f.h.h.h.f.f.f.f.f.f.f.f.u.u.f.W B.NXSXGXGXGXGXGXGXGXGXSXBXoXW :.:.:.:.:.:.=.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W %. HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHX$.R W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ` e !.CXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFX+Xd ,.f.h.h.h.f.f.f.f.f.f.u.u.u.f.,.T :XFXGXGXGXGXGXGXGXGXGXSXNXE.f :.:.:.:.:.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W R $.HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHX~ ..W W W W W W W W W W W W W W W W W W W W E ~ ~ a _ aXFXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFX7XV.s.:.=.:.,.u.f.f.f.f.u.u.u.r.~ s ~.VXSXGXGXGXGXGXGXGXGXGXAXhXV.d :.:.=.=.=.=.=.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W O.E HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXg $.T W W W W W W W W W W W W W W W W W W W E ~ ~ e G.hXAXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXVXpX*X_.Z.x.t.:.` ~ ~ ~ ~ ~ ' x.*XVXSXGXGXGXGXGXGXGXGXGXGXDXuXw.W :.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W T $.; HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHX %.R W W W W W W W W W W W W W W W W W W W W ~ d T qXgXBXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXFXBXNXaX>X,X[._.T.T.E.|.:XNXCXSXGXGXGXGXGXGXGXGXGXGXSXVX Xd =.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W R %.HXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHX@.W W W W W W W W W W W W W W W W W W W W W ~ R ` s.H.oXkXNXNXCXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXSXDXFXCXCXBXVXVXBXCXFXSXSXGXGXGXGXGXGXGXGXGXGXGXAXhXm.a :.` =.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W W W W W @.HXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXx @.T W W W W W W W W W W W W W W W W W W W W ~ ~ y t a _ g.L.oXkXhXVXCXFXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXGXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXBX:Xf ~ ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W T $.h HXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHX%.R W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ d a t a ' s.R.oXnXDXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXZXhXg.y =.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ E ~ E W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXO.~ W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ` ` ~ W a a d ! c #DF943B", +", c #D8913C", +"< c #D8923E", +"1 c #DF953E", +"2 c #E28B23", +"3 c #E38B23", +"4 c #EA9023", +"5 c #EB9023", +"6 c #ED9122", +"7 c #ED9123", +"8 c #EE9123", +"9 c #EE9223", +"0 c #F39421", +"q c #F19423", +"w c #F39523", +"e c #F79521", +"r c #F59422", +"t c #F49623", +"y c #F69622", +"u c #F79623", +"i c #F09324", +"p c #F19424", +"a c #F19525", +"s c #F49624", +"d c #F59625", +"f c #F49725", +"g c #F79624", +"h c #F79724", +"j c #F69725", +"k c #F79725", +"l c #F69726", +"z c #F79726", +"x c #F89621", +"c c #F89722", +"v c #F89723", +"b c #F89724", +"n c #F89824", +"m c #F89825", +"M c #F99825", +"N c #F89925", +"B c #F89926", +"V c #F89927", +"C c #F99927", +"Z c #F0972E", +"A c #F7992A", +"S c #F79A2B", +"D c #F79B2C", +"F c #F69A2D", +"G c #F79D2F", +"H c #F89929", +"J c #F89A28", +"K c #F89A29", +"L c #F99A29", +"P c #F99B29", +"I c #F89A2A", +"U c #F89A2B", +"Y c #F99B2B", +"T c #F89B2C", +"R c #F89C2C", +"E c #F99C2D", +"W c #F99C2E", +"Q c #F89D2E", +"! c #F99D2F", +"~ c #E29335", +"^ c #E49639", +"/ c #E2983F", +"( c #F79F35", +") c #F99E31", +"_ c #F89E32", +"` c #F99E32", +"' c #F9A033", +"] c #F9A035", +"[ c #F9A135", +"{ c #F9A036", +"} c #F9A136", +"| c #F9A137", +" . c #F3A03F", +".. c #F7A43F", +"X. c #F8A139", +"o. c #F9A23A", +"O. c #FAA33B", +"+. c #FAA43E", +"@. c #FAA43F", +"#. c #EF9F41", +"$. c #EEA244", +"%. c #ECA34B", +"&. c #F8A440", +"*. c #F9A541", +"=. c #F9A644", +"-. c #F9A947", +";. c #F0A349", +":. c #F5A648", +">. c #F1A74E", +",. c #F7AA4F", +"<. c #E4A458", +"1. c #E4A55B", +"2. c #E8A95E", +"3. c #F2A950", +"4. c #F4AA52", +"5. c #FBAF55", +"6. c #E4A860", +"7. c #EAAC63", +"8. c #EBAF68", +"9. c #F2AF61", +"0. c #EBB16C", +"q. c #F6B568", +"w. c #E3AF71", +"e. c #EBBE89", +"r. c #E0BC93", +"t. c #E3C199", +"y. c #E6C59D", +"u. c #EAC89E", +"i. c #E7C8A2", +"p. c #EACBA6", +"a. c #EBCFAF", +"s. c #F1CCA0", +"d. c #E7CEB1", +"f. c #ECD1B0", +"g. c #E5D2BB", +"h. c #E8D2B8", +"j. c #DFDFDF", +"k. c #E7D5C1", +"l. c #E7D7C4", +"z. c #E5D7C7", +"x. c #E7DACB", +"c. c #EADAC8", +"v. c #E9DCCC", +"b. c #EDDFCE", +"n. c #E5DDD3", +"m. c #E4DFD9", +"M. c #ECE0D1", +"N. c #E4E1DD", +"B. c #EDE3D8", +"V. c #EAE4DD", +"C. c #ECE5DC", +"Z. c #E2E2E2", +"A. c #E5E2E0", +"S. c #E4E4E4", +"D. c #E7E7E7", +"F. c #EAEAE9", +"G. c gray92", +"H. c #EEEEEE", +"J. c None", +/* pixels */ +"J.J.J.J.J.J.J.1 > J.J.J.J.J.J.J.", +"J.J.J.J.J./ ..| ' ( ~ J.J.J.J.J.", +"J.J.J.< *.{ V $ r U W _ - J.J.J.", +"J.J., o.J 0 # <.w.$.F N H % J.J.", +"J.J.o.T e 1.r.k.x.t.S z B u J.J.", +"J.^ [ Y ! #.z.H.M.n.0.d n m 2 J.", +"J.X.) | =. .h.B.5.f.j.;.v B d J.", +": Q M ` &.>.A.V.p.c.l.4.E n d = ", +"; I b A Z 2.D.s.u.F.a.-.} C w & ", +"J.l g y 6.m.G.q.3.b.Z.,.] D 8 J.", +"J.3 k c %.d.C.v.N.S.y.@.L a * J.", +"J.J.j z x 8.i.g.e.9.+.W t 6 J.J.", +"J.J.+ s h G :.7.O.R B s 7 . J.J.", +"J.J.J.O i f P L K d p 5 J.J.J.", +"J.J.J.J.J.@ 9 q i 4 + J.J.J.J.J.", +"J.J.J.J.J.J.J.X o J.J.J.J.J.J.J." +}; diff --git a/share/pixmaps/bitcoin24.png b/share/pixmaps/bitcoin24.png new file mode 100644 index 00000000..78945b4b Binary files /dev/null and b/share/pixmaps/bitcoin24.png differ diff --git a/share/pixmaps/bitcoin256.png b/share/pixmaps/bitcoin256.png new file mode 100644 index 00000000..02988478 Binary files /dev/null and b/share/pixmaps/bitcoin256.png differ diff --git a/share/pixmaps/bitcoin256.xpm b/share/pixmaps/bitcoin256.xpm new file mode 100644 index 00000000..87bb35cd --- /dev/null +++ b/share/pixmaps/bitcoin256.xpm @@ -0,0 +1,465 @@ +/* XPM */ +static char *bitcoin___[] = { +/* columns rows colors chars-per-pixel */ +"256 256 203 2", +" c #BE741B", +". c #C1761B", +"X c #C6791C", +"o c #CC7C1D", +"O c #D07F1D", +"+ c #C67B21", +"@ c #CC7E21", +"# c #D4821E", +"$ c #D9841F", +"% c #ED8E1D", +"& c #EF911F", +"* c #CF8022", +"= c #D48323", +"- c #DB8621", +"; c #DD8922", +": c #D58729", +"> c #D6882B", +", c #DE8C2A", +"< c #CE8C3C", +"1 c #D28934", +"2 c #D98E32", +"3 c #D28E3C", +"4 c #DF9132", +"5 c #D6903E", +"6 c #DD933B", +"7 c #E58C22", +"8 c #E98F23", +"9 c #E38F2B", +"0 c #E88F28", +"q c #ED9124", +"w c #E6922D", +"e c #EB942B", +"r c #EF982F", +"t c #F59624", +"y c #F89723", +"u c #F79826", +"i c #F89825", +"p c #F1972A", +"a c #F59A2C", +"s c #F89B2B", +"d c #E59534", +"f c #EA9632", +"g c #EE9933", +"h c #E3963B", +"j c #E6993D", +"k c #EC9C3B", +"l c #F49C33", +"z c #F99E32", +"x c #F29E3A", +"c c #F7A037", +"v c #F9A036", +"b c #F5A13C", +"n c #F9A33B", +"m c #CE9147", +"M c #D29245", +"N c #DC9641", +"B c #DD9846", +"V c #D2954B", +"C c #DC9A4B", +"Z c #E59C44", +"A c #EA9E43", +"S c #E39E4B", +"D c #E89F49", +"F c #F09F40", +"G c #EDA145", +"H c #E6A14D", +"J c #EBA34B", +"K c #F4A443", +"L c #F9A642", +"P c #F7A847", +"I c #FAA846", +"U c #F3A64A", +"Y c #F8A748", +"T c #F5A94D", +"R c #FAAA4B", +"E c #E6A454", +"W c #EBA552", +"Q c #EDA856", +"! c #E4A55B", +"~ c #E8A75B", +"^ c #E7A95E", +"/ c #EBA95B", +"( c #F0A751", +") c #F4AB53", +"_ c #FAAE53", +"` c #F4AE5A", +"' c #F8AF59", +"] c #FAB057", +"[ c #F6B15E", +"{ c #FAB25B", +"} c #DFAD6F", +"| c #DCAE77", +" . c #DFB27D", +".. c #E5AA64", +"X. c #E8AB61", +"o. c #E5AE6C", +"O. c #E6B06F", +"+. c #ECB16C", +"@. c #F5B365", +"#. c #FBB562", +"$. c #FBB867", +"%. c #F5B66B", +"&. c #FAB768", +"*. c #F4B86F", +"=. c #FBB96A", +"-. c #E1AE71", +";. c #E5B174", +":. c #EBB573", +">. c #EFB977", +",. c #E5B47A", +"<. c #EEBA7B", +"1. c #F3B770", +"2. c #F3B974", +"3. c #FBBC72", +"4. c #F3BC7B", +"5. c #F8BF7A", +"6. c #FAC079", +"7. c #DCB382", +"8. c #DFBB8F", +"9. c #DABB96", +"0. c #DBBD99", +"q. c #E2B682", +"w. c #E4B985", +"e. c #ECBD84", +"r. c #E3BB8B", +"t. c #EABF8C", +"y. c #F1BE83", +"u. c #E2BE92", +"i. c #D3BDA2", +"p. c #DEC09C", +"a. c #EEC28D", +"s. c #F4C286", +"d. c #F8C282", +"f. c #F3C48B", +"g. c #E7C297", +"h. c #ECC393", +"j. c #E2C29D", +"k. c #EAC69B", +"l. c #ECC89F", +"z. c #F1C694", +"x. c #F2C897", +"c. c #F1CA9B", +"v. c #DBC2A3", +"b. c #D6C2AB", +"n. c #DDC7AD", +"m. c #DEC9AF", +"M. c #D3C4B3", +"N. c #DDCAB3", +"B. c #D2C7B9", +"V. c #D6C9BA", +"C. c #DDCEBB", +"Z. c #DFD0BE", +"A. c #E2C5A2", +"S. c #E8C7A0", +"D. c #E6C9A5", +"F. c #EBCBA4", +"G. c #E2C7A8", +"H. c #E3CAAC", +"J. c #EBCDA9", +"K. c #EFD2AF", +"L. c #F3D1A7", +"P. c #F1D1A9", +"I. c #E4CEB3", +"U. c #E8CFB1", +"Y. c #E1CFBA", +"T. c #E6D0B6", +"R. c #E9D1B4", +"E. c #E4D2BC", +"W. c #EAD4BA", +"Q. c #F4D5B0", +"!. c #F4D9B9", +"~. c #CDCDCD", +"^. c #D5CCC3", +"/. c #D4CFCA", +"(. c #DED2C3", +"). c #D3D1CE", +"_. c #DED6CC", +"`. c #D5D5D5", +"'. c #DBD7D1", +"]. c #DEDAD4", +"[. c #DDDDDC", +"{. c #E3D5C3", +"}. c #E9D7C1", +"|. c #EBD9C4", +" X c #E1D6CA", +".X c #E3D9CD", +"XX c #EADDCD", +"oX c #E1DBD4", +"OX c #E8DFD4", +"+X c #E1DEDB", +"@X c #EDE3D7", +"#X c #E3E1DE", +"$X c #E8E3DC", +"%X c #F6E5D2", +"&X c #F4EBDF", +"*X c #E4E4E4", +"=X c #ECE7E2", +"-X c #EDE9E4", +";X c #ECECEC", +":X c #F0EBE7", +">X c #F4F4F4", +",X c #FEFEFE", +"X>X>X>X;X;X*X[.`.r.n n z v v v v c x l p l x x c c v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X>X>X>X>X>X;X*X[.`.@.n n v v v v v c g E | S k f r l l l z z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i e X>X,X,X,X,X>X>X;X*X_.R n v v v v v v x e 0.`.`.V.p.;.H f e e p l l z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y , X>X,X,X,X,X>X>X;X*XI.L n v v v v n n x g V.`.[.[.[.[.[.(.p.;.S f r l z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u u y X,X,X,X,X,X>X>X;X*Xa.n n v v v n n n l A `.[.*X*X-X-X*X*X*X[.`.V.9.K z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X,X,X,X,X,X>X>X-X[.%.n n n n n n n b p o.[.*X;X;X;X>X;X;X*X*X[.`.~.T z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y 0 X>X,X,X,X,X,X>X;X*XoXR L n n n n n n b g u.*X-X;X>X>X>X>X>X;X*X*X[.N.L n z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y X>X,X,X,X,X>X>X;X*XI.L L n n n n n n b g C.*X;X>X>X,X,X,X>X>X;X*X[.g.L n z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X,X,X,X,X,X>X>X;X*Xh.L L n n n n n n l G [.*X;X>X,X,X,X,X>X>X;X*X[.2.n n z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y w X,X,X,X,X,X>X>X-X[.%.L n n n n n n b l o.*X;X>X>X,X,X,X,X,X>X;X*X]._ n v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y X>X,X,X,X,X,X>X;X*XoXR L n n n n n n b g j.*X;X>X>X,X,X,X,X,X>X;X*XE.I n v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y t X>X,X,X,X,X>X>X;X*XT.I L n n n n n n b k Z.*X;X>X,X,X,X,X,X>X>X;X*Xl.L n v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y ; X,X,X,X,X,X>X>X;X*Xh.L L n n n n L L x G [.*X;X>X,X,X,X,X,X>X>X;X*X4.n n v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X>X,X,X,X,X,X>X>X-X[.%.L L n n n L L L l ;.*X;X>X>X,X,X,X,X,X>X;X*X[._ L n v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y q X>X>X>X;X;X;X;X*X*X*X*X].N.q.! d e e r p q ,.-X;X>X>X,X,X,X,X,X>X;X*XoX_ I L n L L L L K g j.*X;X>X>X,X,X,X,X,X>X;X*XE.Y L n v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X>X>X>X>X>X>X>X;X;X;X;X*X*X*X*X_.I.r.o.Z w D.;X>X>X,X,X,X,X,X,X>X;X*XW.R I L L L L L L K k Y.*X;X>X,X,X,X,X,X>X>X;X*Xl.L L n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y q X>X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X*X*X*X*X$X}.=X>X>X>X,X,X,X,X,X,X>X;X*Xx.I I L L L L L L x J [.*X;X>X,X,X,X,X,X>X>X;X*X4.L n n v v v v v z z z z z z s s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X;X>X>X>X>X,X,X,X,X,X,X,X>X>X;X&.L L L L L L L L x ;.*X;X>X>X,X,X,X,X,X>X;X*X[.' L n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X>X>X@Xb l x x K L L L L k j.*X;X>X>X,X,X,X,X,X>X;X*XE.R L n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X:XW.g.;.H k k k b F k {.;X>X>X,X,X,X,X,X>X>X;X*XS.I L n n n n v v v v v z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X*X+XE.j.,.~ j A =X;X>X>X,X,X,X,X,X>X>X;X*X4.I L n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X;X*X*X*X*XXX}.;X>X>X,X,X,X,X,X,X>X>X;X#X{ I n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X;X;X;X>X>X>X,X,X,X,X,X,X,X>X>X;X|.R I n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X>X>X;XF.L L n n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X,X,X,X,X,X,X,X,X,X,X,X>X>X;X@.a x b b n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X|.e.G g l c b n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 0 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X+XG...k g l b n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X*X*X(.w.A g l c c v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X*X'.u.A r l x c v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X*X].u.k r l c v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X*X_.q.g p l z v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 7 X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X[.C.W p l c v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X*X*X[.w.r a l z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X-X-X-X*X*X-X;X;X;X;X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X*X[.H.g a z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 0 X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xf.3.x.R..X+X*X*X*X*X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X*X(.k p z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X$.{ { { $.3.f.F.{.[.*X*X*X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X_.W p z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t @ X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X|.{ ] _ ] { { { { $.3.h.R..X*X*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X'.k p z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 0 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ._ ] _ _ _ _ ] { { { #.$.$.f.T.oX*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X_.l a z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs._ _ _ _ _ _ _ _ _ ] { { { { { =.l..X*X*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*XH.t z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X+X&.] _ _ _ _ _ _ _ _ _ _ _ _ ] { { { #.k.oX*X-X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.:.t z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.{ { _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ] _ { J.*X*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X'.l s z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XF.{ { _ _ _ _ _ _ _ _ ] _ _ _ _ _ _ _ _ _ _ _ y.oX*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.t.u z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.{ ] _ _ _ _ _ ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ ' .X*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X'.z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X].&.{ ] _ _ _ ] ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ R R oX*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.:.u z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ _ _ _ _ ] ] ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ I @.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XD.s z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XF.{ { _ ' ] ] ] ] ] { { { ] ] ] _ _ _ _ _ _ _ _ R R _ n k.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X_.n z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.{ { ] ] ] ] { { { { { { ] ] ] _ _ _ _ _ _ _ _ R R R I T +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.T z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.{ { ] ] ] { { { { { { { ] ] ] _ _ _ _ _ _ _ _ _ R R R K D.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.%.z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ ] ] { { { { { { { { { { ] ] ] _ _ _ _ _ _ _ _ R R R K e.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.<.v v z z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { { { { { { { { { { { { { { ] ] ] _ _ _ _ _ _ _ _ R R K +.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X<.n v v z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.#.{ { { { { { { { { { { { { { ] ] ] ] _ _ _ _ _ _ _ _ R U / *X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xe.n n v v z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.#.{ { { { { { { { { { { { { { ] ] ] ' _ _ _ _ _ _ _ _ R K +.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X<.n n v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.$.#.{ { { { { { { { { { { { { { { ] ] ] ] _ _ _ _ _ _ _ T K ,.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.>.n n v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t @ X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.#.#.{ { { { { { { { { { { { { { { ] ] ] ] _ _ _ _ _ _ _ T G j.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.%.n n v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.#.{ { { { { { { { { { { { { { { { { ] ] ] _ _ _ _ _ _ _ T J X-X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X]._ L n v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X#X3.#.{ { { { { { { { { { { { { { { { { { ] ] ] _ _ _ _ _ ) G ..*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X{.R L n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X|.=.#.{ { { { { { { { { { { { { { { { { { { ] ] ' _ _ _ _ T k E.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XH.L L n v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xc.] { { { { { { { { #.{ { { { { { { { { { { ] ] ] _ _ _ ( A w.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.a.L n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xx.( Q ( ) ` [ [ { #.#.#.{ { { { { { { { { { { ] ] _ ) T D o.*X;X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.[ L n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;XOXI.u.O./ Q Q ` ` [ [ [ { { { { { { { { { ] ' ) ( J H r.*X-X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XE.R I n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X*X*X_.H.r.;.X./ Q Q ) ) ` ` ` ` ` ) ) ( J H W ,.{.*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.y.I L n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X;X*X*X*X*X].(.H.u.q.;.^ ^ ~ ~ E E ~ o.r.G. X*X*X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X_._ Y L n n n n n v v v z z z z z z z s s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i u t @ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X;X;X*X*X*X*X*X*X[.]..X X XoX+X*X*X*X-X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.f.R I n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X;X;X-X-X*X*X*X-X;X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X;X*X X_ R L n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X;X;X;X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.%.R I L n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i t - X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X[.k.R R L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X*X[.l.] _ I L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X[.l.{ _ Y L L L n n n n n n n n v v v v v v z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X*X].h.{ _ R L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X*X[.T.3.{ ] R I L L L L L n n n n n n n n n v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X;X;X;X;X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*XW.s.#.{ _ R I I L L L L L L n n n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X-XQ.|.OX*X*X*X*X*X;X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X&X!.L.d.#.{ ] R R I I I L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;XXX3.3.3.s.c.R..X[.*X*X*X-X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X%X{ L R _ _ R R R I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-XK.&.=.=.&.=.3.3.d.c.R..X[.*X*X*X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;XJ.J K Y R R Y I I I I L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.$.#.#.#.#.&.&.=.=.3.3.f.F.}.+X*X*X*X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;XOX:.K U R R I I I I I L L L L L L n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X+X3.$.#.{ { #.#.#.#.$.$.&.=.=.3.6.c.W.+X*X*X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*Xj.K K R R I I I I I L L L L L n n n n n n n n v v v v v v z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i u t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.&.#.{ { { { #.#.#.#.#.#.#.#.$.$.=.=.5.J..X*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*XH.K K R R I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i u t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.#.#.{ { { { #.#.#.#.#.#.#.#.{ #.#.$.$.$.=.z.{.*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X*XC.U K R I I I I I L L L L L L n n n n n n n n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i u q * s u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u u u u s s s s s s s s s s s z z z z z z z v v v v v n n n n n n n n L L L L L L I I K A Z.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.#.#.{ { { { { #.#.#.#.{ { { { { { { #.#.#.#.$.z.{.*X*X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*XC.b K Y I I I I L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i u q + X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.3.#.{ { { { { { #.#.#.{ { { { { { { { { { { #.#.#.$.F.+X*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.H.b P I I I I I L L L L L n n n n n n n n n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.$.#.{ { { { { { { { { { { { { { { { { { { { { { { #.{ 2.{.*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.e.b Y I I I I L L L L L L n n n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.#.#.{ { { { { { { { { { { { { { { { { { { { { { { { { { { U.*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X].T L Y I I I I L L L L L L n n n n n n n n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.#.{ { { { { { { { { { { { { { { { { { { { { { { { { ] { { _ R.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X*XD.L R I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.#.{ { { { { { { { { { { { { { { { { { { { { { ] ] ] ] ] { ' R T.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.` L I I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.$.#.{ { { { { { { { { { { { { { { { { { { { ] ] ] ] ] ] ] _ ] _ R oX*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.g.n I Y I I I I L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { { { { { { { { { { { { { { { { { { { { ] ] ] ] ] _ _ _ _ _ ] Y <.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X(.I I I I I I L L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i u t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.{ { { { { { { { { { { { { { { { { { { ] ] ] ] ] ] _ _ _ _ _ _ _ _ T .X-X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.[ L I I I L L L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i u q = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.{ { ] { { { { { { { { { { { { { { ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ P g.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.e.n I L L L L L L L L L L n n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ ] ] { { { { { { { { { { { ] ] ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ Y +.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xg.L I L L L L L L L L L n n n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { ] ] ] { { { { { { { { { ] ] ] ] ] ' _ _ _ _ _ _ _ _ _ _ _ _ _ _ T Q #X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XD.I I L L L L L L L n n n n n n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.{ { ] ] ] ] { { { { { { { ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Y W +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XI.I I L L L L L n n n n n n n n n n n n n n n v v v v v v z z z z z z z s s s s s s s s s s u u u u u i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.{ ] ] ] ] ] { { { { { ] ] ] ] ] ' _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R T W +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XE.I L L L L n n n n n n n n n n n n n n v v v v v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i u q ; X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ _ _ ] ] ] ] { ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R K X.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XE.I L n n n n n n n n n n n n n n n n v v v v v v v v v z z z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i t q @ X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { _ _ _ ] ] ] ] ] ] ] ] ' _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R x q.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XD.R L n n n n n n n n n n n n n n n v v v v v v v v v z z z z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i t q X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.{ ] _ _ _ ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R T k G.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XS.I L n n n n n n n n n n n n n v v v v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i t q X>X>X,X,X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X#X&.{ _ _ _ _ _ ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R K A oX;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xh.L L n n n n n n n n n n v v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s u u u i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X|.{ ] _ _ _ _ _ ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R R U k u.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.2.L L n n n n n n n n n v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s u u u u i i i i i i i u q = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xc.R _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R R R T k D +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.' L n n n n n n n n v v v v v v v z v v z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s u u u u i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xf.K G G U ) ) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R R R R U A j {.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X{.R L n n n n n n v v v v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-XXXH.w.X.J J J T ) ) ) _ _ _ _ _ _ _ _ R R R R R R R R R R R Y K k D Y.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.L L n n n n v v v v v v v v z z z z z z z z z z z z z s z s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i u t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X#X(.A.q...H J J U U T T T T R R R R R R R R R Y Y U K k A ;..X*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X[.4.L n n n v v v v v v v v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i t q * X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X;X*X*X*X[.(.H.u.,.^ J D G A J K K U U U U K k k k A E w.Y.*X*X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X]._ L n v v v v v v v v v v z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i t q X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X;X;X;X-X*X*X*X*X[._.N.A.u.;.;...E E E E ..;.q.j.I.+X*X*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XH.I L n v v v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i t 8 X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X-X*X*X*X*X*X*X*X+X+X+X+X*X*X*X*X*X;X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.1.L n v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i u q ; X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X XR L n v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i t q X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X[.a.L n v v v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i t 8 X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X]._ L n v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i u q ; X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.a.L n v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X_.R L n z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.2.L n z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u s u u u u u u u u i i i i i i i i i i i i i i i i i i t q = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.D.L L v z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X XR L n z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i u q 7 X>X,X,X,X,X,X,X,X>X>X>X>X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X'._ I n z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u i u u i i i i i i i i i i i i i i i i i i i i i i t q o X>X,X,X,X,X,X,X>X>X>X=X;X-X-X-X;X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X].%.L L z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X,X>X>X;X=X=.5.c.W.oX*X*X-X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X*X*X_.%.I L z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X>X,X,X,X,X,X>X>X;X|._ _ _ { #.4.l.}.$X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X[.E.{ I L v z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i u i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X,X,X,X,X,X>X>X;X*XF.R R R R _ _ { { { 4.-X>X>X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X;X;X*X*X[.k._ I n z z z s s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 X,X,X,X,X,X>X>X;X*X4.R I I I I R R R b U -X>X>X,X,X,X,X,X,X,X,X>X>X>X>X>X;X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X;X;X;X-X*X*X[.T.*.R L n z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X>X;X*X+X] R I L I I I I P x t.;X>X>X,X,X,X,X,X,X,X>X>X;X;X;X;X-X-X-X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X*X*X*X[.].U.4.R I L v z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 7 X>X,X,X,X,X>X>X;X*XE.R Y L L I I I I K k I.-X;X>X,X,X,X,X,X,X>X>X;X|.f.J.W..X[.[.*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X[._.I.h.#.R L L n z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q . X,X,X,X,X,X>X>X;X*Xl.I I L L L I I P K A oX-X>X>X,X,X,X,X,X>X>X;X;Xs.R _ _ { #.4.y.S.l.T.{.{. XoXoXoXoX].oX{.{.E.k.a.2.{ _ I L n v z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 7 X,X,X,X,X,X>X>X;X[.2.I I L L L L I L x ^ *X;X>X>X,X,X,X,X,X>X>X;X*X#.I I I I Y I R I _ R _ ] { { [ { { { { ] _ R R I I L n n v z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q . X>X,X,X,X,X,X>X;X*X]._ Y L L L L L I L k r.*X;X>X>X,X,X,X,X,X>X;X-X.XR L n n n n n n L L L L L L L n L n n n L n n n c v z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 7 X>X,X,X,X,X>X>X;X*XT.R I L L L L L L K k H.*X;X>X>X,X,X,X,X>X>X;X*XJ.L L n n n n n v v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X,X,X,X,X,X>X>X;X*Xk.I I n L L L L L b k ].*X;X>X,X,X,X,X,X>X>X;X*Xy.L n n n n v v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 X,X,X,X,X,X>X>X-X[.2.L L n L L L L L l ^ [.-X>X>X,X,X,X,X,X>X;X*X[.[ L n n n v v v v v v v z z v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X,X,X,X,X,X>X;X*X]._ L L n L L L L K g r.*X;X>X>X,X,X,X,X,X>X;X*X{.R L n v v v v v v v z z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X,X,X,X,X>X>X;X*XE.I L n n n L L L b g H.*X;X>X>X,X,X,X,X>X>X;X*XF.L L v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 8 X>X>X,X>X>X>X;X*Xk.L L n n n n L L x k _.*X;X>X,X,X,X,X,X>X>X;X*Xy.n n v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q # X>X>X>X>X;X*X[.2.L L n n n n n b l ~ [.-X>X>X,X,X,X,X,X>X;X*X[.' L n v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s s u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 X>X,X,X,X,X,X>X;X*X{.I n c v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X>X>X;X*XF.L n v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X>X,X,X,X,X>X>X;X*X4.n n z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 .L n n n n n n b l E [.*X;X>X>X,X,X,X>X>X;X*X[.' n v z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X>X>X>X>X>X;X*X{.I n z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X>X>X;X;X*X[.S.n n z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 c #8F6A16", -", c #816218", -"< c #88691C", -"1 c #926D12", -"2 c #936F1C", -"3 c #997417", -"4 c #94721E", -"5 c #9B761C", -"6 c #9F781C", -"7 c #A17B1E", -"8 c #826622", -"9 c #916E20", -"0 c #967425", -"q c #9D7420", -"w c #9C7923", -"e c #997728", -"r c #99792C", -"t c #A37D23", -"y c #A37F2C", -"u c #A68125", -"i c #AB8225", -"p c #A5832B", -"a c #AA852C", -"s c #B28A2C", -"d c #A58233", -"f c #AC8734", -"g c #AE8C33", -"h c #AC8C3C", -"j c #B28C33", -"k c #B98E34", -"l c #B28D3D", -"z c #B59136", -"x c #BC9335", -"c c #B3913E", -"v c #BC933A", -"b c #BF9A3D", -"n c #C19235", -"m c #C2953C", -"M c #C39B3C", -"N c #CA9C3D", -"B c #B59343", -"V c #BE9642", -"C c #B69A44", -"Z c #BD9A45", -"A c #B49649", -"S c #BB9A49", -"D c #BB9F52", -"F c #BFA256", -"G c #C49C43", -"H c #CA9D41", -"J c #C59D4A", -"K c #C99E4D", -"L c #C3A144", -"P c #CDA244", -"I c #CFAA47", -"U c #C3A14D", -"Y c #CDA24A", -"T c #CCAB49", -"R c #D2A644", -"E c #D2A54B", -"W c #D6AA4C", -"Q c #DAAE4E", -"! c #DAB04F", -"~ c #C7A656", -"^ c #CDA452", -"/ c #CFAC52", -"( c #C0A65E", -") c #CEA75A", -"_ c #CCAC59", -"` c #D2AB53", -"' c #DCAF52", -"] c #D6AD5A", -"[ c #D9AE5B", -"{ c #DCB556", -"} c #DFB855", -"| c #D6B25F", -" . c #DCB35C", -".. c #DEBE5E", -"X. c #E2B656", -"o. c #E1B55A", -"O. c #E6BC5D", -"+. c #E9BD5E", -"@. c #C3AA63", -"#. c #CCAD62", -"$. c #D4AF62", -"%. c #CDB565", -"&. c #CEB46D", -"*. c #D7B164", -"=. c #DBB362", -"-. c #D6BD64", -";. c #DDBA64", -":. c #D3B66C", -">. c #DFB86B", -",. c #CEB772", -"<. c #D0B771", -"1. c #D4BA73", -"2. c #D9BE77", -"3. c #D6BE79", -"4. c #D8BF7A", -"5. c #E4BB62", -"6. c #E9BF64", -"7. c #E4BC69", -"8. c #E9BF69", -"9. c #E0BB71", -"0. c #E9C05E", -"q. c #D2C279", -"w. c #DBC27C", -"e. c #E2C667", -"r. c #EDC364", -"t. c #E3C16E", -"y. c #ECC46C", -"u. c #EDCC6C", -"i. c #F1C764", -"p. c #F5CA66", -"a. c #F9CD67", -"s. c #F5CC6A", -"d. c #F9CD6B", -"f. c #FBD36F", -"g. c #EDC572", -"h. c #E5CF77", -"j. c #ECCA74", -"k. c #E0C67E", -"l. c #EFCE78", -"z. c #F6CE72", -"x. c #FBCF71", -"c. c #F4CE79", -"v. c #F4D273", -"b. c #FCD473", -"n. c #F4DC75", -"m. c #FEDA74", -"M. c #F6D77C", -"N. c #FBD47A", -"B. c #F1DA7B", -"V. c #FDDA7C", -"C. c #FEE27D", -"Z. c #DDC683", -"A. c #DFC884", -"S. c #E4CA84", -"D. c #E3CC89", -"F. c #E7D183", -"G. c #EFD280", -"H. c #EFDC82", -"J. c #ECD48D", -"K. c #EFDA8C", -"L. c #F9D783", -"P. c #F2DF83", -"I. c #FCDB83", -"U. c #F5DC8F", -"Y. c #FADD8B", -"T. c #EBD593", -"R. c #EFDA99", -"E. c #F3DD93", -"W. c #F3DF9F", -"Q. c #FFE385", -"!. c #FEE986", -"~. c #FDE48C", -"^. c #FEEC8E", -"/. c #ECE199", -"(. c #F6E591", -"). c #FEE494", -"_. c #FEEB93", -"`. c #FEE69A", -"'. c #FFEB9B", -"]. c #FFF197", -"[. c #FFF39B", -"{. c #FEF99B", -"}. c #F6E2A2", -"|. c #F9E5A5", -" X c #F7E9A5", -".X c #FEECA4", -"XX c #FBE7A8", -"oX c #FDEAAB", -"OX c #F7F2AA", -"+X c #FEF2AC", -"@X c #FDF4B4", -"#X c #FFFABA", -"$X c #FFFEC2", -"%X c None", +"32 32 102 2", +" c #CC7D1D", +". c #D5831F", +"X c #D48221", +"o c #D98621", +"O c #DC8820", +"+ c #DC8D2C", +"@ c #D98F36", +"# c #D68F39", +"$ c #DD943E", +"% c #E28B23", +"& c #E98F24", +"* c #E18F2D", +"= c #ED9124", +"- c #EC942A", +"; c #F59624", +": c #F89724", +"> c #F79827", +", c #F89825", +"< c #F0962B", +"1 c #F59A2D", +"2 c #F99B2B", +"3 c #EC9732", +"4 c #EC9A37", +"5 c #E2963B", +"6 c #E6983A", +"7 c #EC9C3B", +"8 c #F69D33", +"9 c #F99E32", +"0 c #F49E3A", +"q c #F9A036", +"w c #F6A13C", +"e c #F9A33B", +"r c #D79341", +"t c #DC9641", +"y c #E39A43", +"u c #EA9D42", +"i c #EFA041", +"p c #EDA34B", +"a c #F5A443", +"s c #F9A643", +"d c #FAA846", +"f c #F2A64C", +"g c #F9AA4B", +"h c #E5A251", +"j c #ECA756", +"k c #EBA758", +"l c #FAAF57", +"z c #FBB057", +"x c #FBB25B", +"c c #DFB179", +"v c #E4AA65", +"b c #EBAE64", +"n c #E9AF69", +"m c #FBB665", +"M c #F1B46A", +"N c #F8B96D", +"B c #E5B071", +"V c #EBB777", +"C c #EEB877", +"Z c #E7B478", +"A c #EBB97D", +"S c #F0B671", +"D c #F2B871", +"F c #EFBC80", +"G c #E6BD8D", +"H c #EDBF88", +"J c #E6BF90", +"K c #F1C187", +"L c #F1C288", +"P c #E5C093", +"I c #EEC493", +"U c #E1C19B", +"Y c #E9C69C", +"T c #ECC89D", +"R c #F1C897", +"E c #DFC5A4", +"W c #DBCBB8", +"Q c #E2C7A7", +"! c #EBCBA6", +"~ c #E6CBAB", +"^ c #E9D2B7", +"/ c #E5D1B9", +"( c #EBD6BD", +") c #EFD9BE", +"_ c #DDD0C2", +"` c #DCD7D2", +"' c #DEDEDE", +"] c #ECDAC5", +"[ c #EDDECB", +"{ c #E9E0D5", +"} c #E7E0D9", +"| c #E9E2DB", +" . c #EFE8DF", +".. c #E5E5E5", +"X. c #EBE7E2", +"o. c #EFEAE6", +"O. c #ECECEC", +"+. c #F2ECE6", +"@. c #F1F0EE", +"#. c #F4F4F4", +"$. c #FBFBFB", +"%. c None", /* pixels */ -"%X%X%X%X%X%X%X%X%X%X%X%Xp t 6 5 w t w %X%X%X%X%X%X%X%X%X%X%X%X%X", -"%X%X%X%X%X%X%X%X%Xu u x I X.0.s.u.0.W x 7 4 %X%X%X%X%X%X%X%X%X%X", -"%X%X%X%X%X%X%Xy i I i.a.f.m.m.b.f.s.a.s.i.W 7 > %X%X%X%X%X%X%X%X", -"%X%X%X%X%X%Xt M 0.a.m.m.m.m.f.d.p.p.p.f.d.f.i.b 1 < %X%X%X%X%X%X", -"%X%X%X%X%X7 ! d.f.f.m.f.+.W P R I Q 5.v.V.V.z.f.{ 5 + %X%X%X%X%X", -"%X%X%X%Xu X.f.m.m.f.' H s ~ V y _ Z J o.g.L.L.Q.!.e.5 X %X%X%X%X", -"%X%X%Xu X.b.C.m.+.N m n t }.3.> }.w.V 5.y.y.Y.[.^.^.-.1 + %X%X%X", -"%X%Xt P m.N.m.X.v v v k 6 }.1.: /.4.c 7.N.N.v.!.{.{.^.L & %X%X%X", -"%X%Xg Y.Y.V.+.m k a t t : }.1.% }.1.r | l.B.M.b.!.{.^.n.7 X %X%X", -"%Xp -._.'.Y.' Y n D.}.}.|.oXXX|.oX XT.w.F _ j.v.v._.^.C.T & @ %X", -"%Xa (.'.'.9.[ [ K S.}.oXoXoXoXXXoXoXoXoX XD / s.d.v.!.C.v.3 o %X", -"%XU '.'.Y.[ [ [ [ J f <.oXoX( 2 f S J.oXoXT.j r.s.i.C.C.C.z X %X", -"p e.'.'.F. .=.=.=.=.) 1.oXoX@.f . .F oXoX}.a +.i.i.b.C.m.I X O ", -"u w.'.[.j.5.8.7.7.7.] 2.oXoX@.y W c &.oXoXZ.k r.s.i.s.V.m.} = o ", -"u H.[.{.y.8.y.g.8.g.7.2.oXoXA.@.&.D.oXoXT.e G +.O.O.5.V.m.0.- o ", -"u !.].[.r.8.y.g.g.g.7.4.oXoXoXoXoXoXoXoXoX<.y W X.o.o.m.m.0.- o ", -"u B._._.5.5.8.y.g.c.g.w.oXoX,.h A F <..XoXoX1.k ' ' ' V.N.r.- ", -"u u.Q.~.r.6.z.N.V.I.v.k.oXoX@.B | _ c 1.oXoX}.a ' ' O.I.b.O.= o ", -"u ..Q.Q.v.i.s.c.N.L.l.Z.oXoX@.B t.=.S &.oXoXXXy Y R +.N.b.Q % o ", -"t T C.I.I.6.u.z.z.5.S 1.oXoX@.e B h D |.oXoXS.f Y Y 6.d.d.n X O ", -"%Xs m.V.Q.r.r.z.5.<.}.oXoXoXXXW.}.oXoXoXoXW.h G H R a.p.s.7 %X", -"%X7 O.V.V.v.+.r.` 4.oXoXoXoXoXoXoXoXXXR.<.h v N N o.a.p.Q = %X", -"%Xw x v.v.v.r.+. .Z l d e }.Z.r }.3.d l V G n n R a.s.a.s X O %X", -"%X%X6 { v.l.v.+.O.5.=.^ d }.4.9 }.1.f J G m m G d.d.x.Q = %X%X", -"%X%X%Xs u.v.v.v.r.6.o. .l }.4.9 W.4.l ^ ^ J ) c.N.N.y.7 X O %X%X", -"%X%X%X5 z v.v.M.I.g.;. .J 1.#.B 1.#.) 7.$.S..X'.W.Y.j $ %X%X%X", -"%X%X%X%X5 b N.Y.~.).Y.j.5.$.=.=.$.*.2.J.@X$X#X#XoXC $ %X%X%X%X", -"%X%X%X%X%X3 z U.@X+X`.`.`.(.E.E.E.|.@X@X#X#X#X/.j % %X%X%X%X%X", -"%X%X%X%X%X%Xw a q.OX|.).`._.'.'.XX.X.X+X+X X%.w X o %X%X%X%X%X%X", -"%X%X%X%X%X%X%X%Xw a _ j.~.~.).).`.`.`.F._ t & . # %X%X%X%X%X%X%X", -"%X%X%X%X%X%X%X%X%X%X4 3 t z L U Z z t 1 $ . 8 %X%X%X%X%X%X%X%X%X", -"%X%X%X%X%X%X%X%X%X%X%X%X%X< ; & + + , 8 %X%X%X%X%X%X%X%X%X%X%X%X" +"%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.%.%.%.%.%.t 5 5 $ %.%.%.%.%.%.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.%.%.r u w q 9 9 9 8 4 # %.%.%.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.y s e 9 2 , , , : > 2 9 q 5 %.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.s q 2 , , , , : , > 2 2 > > 2 9 %.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.t e 1 , , , , : : ; > 2 9 9 2 , , > 2 + %.%.%.%.%.%.", +"%.%.%.%.%.$ e 2 , , , , , , ; u u 8 1 1 2 > , , > > + %.%.%.%.%.", +"%.%.%.%.%.e 2 , , : > ; ; > < ` ` 0 c n 1 2 , , , > , %.%.%.%.%.", +"%.%.%.%.e 1 , , , , ; h v - 3 ..! w ' _ 9 2 > , , , > : %.%.%.%.", +"%.%.%.6 q , : , > 2 > W ..| [ #.H V ..D 9 9 2 , , , , , % %.%.%.", +"%.%.%.e 2 , > 2 2 2 9 b ! #.$.$.#.#.#.Y i 1 2 > , , , > ; %.%.%.", +"%.%.@ q > 2 2 2 9 q e q 0 o.$.+.) { #.#.| b 2 2 , , , , : X %.%.", +"%.%.4 9 2 2 9 q e e s w b O.#.( m x I @.$...f > > , , , : & %.%.", +"%.%.8 > 2 2 9 e s d g a P #.#.L x l a [ $.#.A 2 2 , : , , ; %.%.", +"%.+ 1 , , 2 2 q e d g f / $.#.T n k Z o.$.O.M 9 2 > , , , ; X %.", +"%.* 2 , , , 2 9 q e s f X.$.#.O.O.O.#.$.+.Y g e 9 2 , , , ; o %.", +"%.* 2 , , , 2 2 q e w n O.$.[ R ( O.$.$.[ d s e 9 2 2 , , ; o %.", +"%.+ 2 , , , > 2 8 8 1 G #.#.T m m N ] #.#.~ s e e 9 2 > : ; X %.", +"%.%.> , , , , 2 < v B [ $.O.m z z s b #.$...g e e q 9 2 ; = %.%.", +"%.%.= : , , , : 7 ' O.#.$.@.C j p u ~ #.$.} g q 9 9 2 2 ; % %.%.", +"%.%.o , , , , : 0 G ^ .$.#.O.X.{ X.#.$.#.Y e 9 2 2 > , ; %.%.", +"%.%.%., : , , , 2 2 2 M O.) ] #.#.#.#.O./ d 9 2 > , , ; = %.%.%.", +"%.%.%.& ; , , , , 2 ; Q ..g F O.K A H S s 9 2 > , : , ; o %.%.%.", +"%.%.%.%.; ; , , , , 2 E _ d ' ..d q q 9 2 > , : , , ; = %.%.%.%.", +"%.%.%.%.%.; : , , , 2 q d g U J e 2 2 > , , , , , ; = %.%.%.%.%.", +"%.%.%.%.%.o ; : , , , 2 9 q 9 q 9 > , : , , , , ; = . %.%.%.%.%.", +"%.%.%.%.%.%.. ; ; , , > 2 2 2 > , , , , , , , ; = %.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.= ; : > 2 2 , , : , , , , ; ; & %.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.. = ; > : , , , , ; ; = = X %.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.%.%. % = ; ; ; ; & O %.%.%.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.%.%.%.%.%. X X %.%.%.%.%.%.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%." }; diff --git a/share/pixmaps/bitcoin512.png b/share/pixmaps/bitcoin512.png new file mode 100644 index 00000000..37265fdc Binary files /dev/null and b/share/pixmaps/bitcoin512.png differ diff --git a/share/pixmaps/bitcoin64.png b/share/pixmaps/bitcoin64.png new file mode 100644 index 00000000..a3a206eb Binary files /dev/null and b/share/pixmaps/bitcoin64.png differ diff --git a/share/pixmaps/bitcoin64.xpm b/share/pixmaps/bitcoin64.xpm new file mode 100644 index 00000000..851829d4 --- /dev/null +++ b/share/pixmaps/bitcoin64.xpm @@ -0,0 +1,242 @@ +/* XPM */ +static char *bitcoin__[] = { +/* columns rows colors chars-per-pixel */ +"64 64 172 2", +" c #8F6319", +". c #8F6A1A", +"X c #90651A", +"o c #916C1A", +"O c #AF7C1E", +"+ c #B1781E", +"@ c #9A7026", +"# c #AC801F", +"$ c #B1811F", +"% c #A9812B", +"& c #B08320", +"* c #BB8621", +"= c #BD8E22", +"- c #A58132", +"; c #FC8400", +": c #FD8A03", +"> c #FD8E0C", +", c #FF910E", +"< c #F98F14", +"1 c #F79117", +"2 c #FD9314", +"3 c #FC951B", +"4 c #FE9A1D", +"5 c #CA8E22", +"6 c #CC8E2A", +"7 c #D48D23", +"8 c #C39223", +"9 c #CE9925", +"0 c #D19C25", +"q c #D19329", +"w c #D5992B", +"e c #DD9D33", +"r c #D69F3C", +"t c #E29425", +"y c #E79925", +"u c #EA9926", +"i c #E69A2C", +"p c #F79625", +"a c #F99524", +"s c #F79825", +"d c #F89825", +"f c #F3962A", +"g c #F69B2C", +"h c #F89B2B", +"j c #E19F30", +"k c #EE9B34", +"l c #F49D33", +"z c #F99E32", +"x c #F39F3B", +"c c #DFA731", +"v c #D7A43D", +"b c #DCA63C", +"n c #EEA328", +"m c #FFA225", +"M c #FFAB26", +"N c #F3A529", +"B c #FEA429", +"V c #F4AB2A", +"C c #FFAC2A", +"Z c #FFB325", +"A c #FFB42C", +"S c #FFBB2D", +"D c #E3A335", +"F c #E5A438", +"G c #EDA03D", +"H c #F7A037", +"J c #FAA135", +"K c #F3AB31", +"L c #FEAB31", +"P c #F4A13C", +"I c #F9A33B", +"U c #FDB432", +"Y c #FFBF37", +"T c #FFC12F", +"R c #FFC230", +"E c #FFC03E", +"W c #DFAF41", +"Q c #ECA34D", +"! c #EDA84E", +"~ c #F2A343", +"^ c #FAA642", +"/ c #FAA846", +"( c #F1A74C", +") c #F6A94F", +"_ c #FAAA4A", +"` c #E7A451", +"' c #ECA754", +"] c #EFAA56", +"[ c #ECAC5B", +"{ c #F3AA52", +"} c #FCAE52", +"| c #FBB056", +" . c #FBB25C", +".. c #E7AB61", +"X. c #ECB067", +"o. c #E7B36D", +"O. c #EBB36C", +"+. c #F2B163", +"@. c #FCB460", +"#. c #F0B56B", +"$. c #E3B274", +"%. c #EDB672", +"&. c #EDB877", +"*. c #E2B57C", +"=. c #ECB97B", +"-. c #E4BA83", +";. c #EBBD83", +":. c #E7BF8D", +">. c #EBBD88", +",. c #E9C08C", +"<. c #E7C496", +"1. c #EBC393", +"2. c #EBC997", +"3. c #E7C49A", +"4. c #E9C69A", +"5. c #E3CA9D", +"6. c #E9C89E", +"7. c #DCC9AE", +"8. c #DDCBB2", +"9. c #E3C7A2", +"0. c #E5CAA3", +"q. c #E9CBA3", +"w. c #E5CEAB", +"e. c #E8CEAA", +"r. c #E4D4AC", +"t. c #EBD2AF", +"y. c #E7CFB2", +"u. c #E1D4B4", +"i. c #E8D5B6", +"p. c #E5D7BB", +"a. c #E9D6BB", +"s. c #E5D8B9", +"d. c #EAD8BE", +"f. c #F0D6B4", +"g. c #DFDFC6", +"h. c #E3D6C1", +"j. c #E9D7C0", +"k. c #E6DAC5", +"l. c #EBDCC7", +"z. c #E5DCCA", +"x. c #EADEC9", +"c. c #E8DFD0", +"v. c #D7E2D9", +"b. c #E3E0C9", +"n. c #EEE2CB", +"m. c #E6E1D4", +"M. c #E9E2D3", +"N. c #E4E4DC", +"B. c #E9E5DE", +"V. c #F4EDDE", +"C. c #DFE8E6", +"Z. c #DEEEE8", +"A. c #DFF2F3", +"S. c #DDFFFF", +"D. c #E1E6E0", +"F. c #E8E6E2", +"G. c #E8E9E5", +"H. c #E5EFEC", +"J. c #E8E9EA", +"K. c #EAF3EE", +"L. c #F3F3EB", +"P. c #E7EDF2", +"I. c #E8EEF3", +"U. c #E7F4F7", +"Y. c #E9F0F7", +"T. c #EBF5FD", +"R. c #E4FEFF", +"E. c #ECFCFF", +"W. c #F4F5F4", +"Q. c #F4FFFF", +"!. c #FEFFFF", +"~. c None", +/* pixels */ +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.F L h C C A A A A C C h L e ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.D N C m d d a a p a a p a a d m m C N j ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.- K M m a p s d d d d d d d d d d d d s p d m M V % ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.Y M d a d d d d d d d d d d d d d d d d h h d s a d M U ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.E m 4 a d d d d d d d d d d d d d d d d d d h h h d d d a d M U ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.C 4 a d d d d d d d d d d d d d d d d d h h h h h h d d d d d a m C ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.W S a p d d d d d d d d d d d d d d d d h h h h g g h h h d d d d d p a S c ~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.v M a s d d d d d d d d d d d d d d d h h h h h g z z g h h d d d d d d s a C w ~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.r Z a d d d d d d d d d d d d d d d g 4 : 2 h z z z z z h h h h d d d d d d d a S q ~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.b Z a d d d d d d d d d d d d d d h h 4 x $.l a z H h h H z h h h d d d d d d d d a A w ~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.T a s d d d d d d d d d d d d h h h g : $.R.T.7.a B x f > a H h h d d d d d d d d s a R ~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.U a s d d d d d d d d d d d d h h h h z : e.!.!.p.2 3 8.D.5.' a h h h d d d d d d d d p d A ~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.U M p d d d d d d d d d d h h 1 : : 2 h h p B.!.Q.%., l J.!.R.-.> z h h h d d d d d d d d p C N ~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.S a d d d d d d d d d d h d 3 7.r.O.G p ; k E.!.T.( , [ E.!.T.~ 4 z h h h d d d d d d d d d a S ~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.V d s d d d d d d d d h h h 2 l E.!.Q.T.m.:.q.!.!.l.: : -.Q.!.c.a z z z g h h d d d d d d d d s m A ~.~.~.~.~.~.~.", +"~.~.~.~.~.~.@ S a d d d d d d d h h h h z : *.R.!.!.!.!.Q.!.!.!.V.,.Q d.!.Q.1.2 I z z h h h d d d d d d d d d a S X ~.~.~.~.~.~.", +"~.~.~.~.~.~.U d s d d d d d h h h h h g z a [ 5.M.Q.!.!.!.!.!.!.!.Q.E.!.!.Q.&.; 3 J H z h h h d d d d d d d d s h C ~.~.~.~.~.~.", +"~.~.~.~.~.~.S a d d d d h h h h h h z z z I d > < %.W.!.!.!.!.!.!.!.!.!.!.!.W.s.[ > 4 H g h h d d d d d d d d d a S ~.~.~.~.~.~.", +"~.~.~.~.~.i M p d d d h h h h g z z z z J H I I J > x.!.!.!.!.Q.T.E.Q.!.!.!.!.!.E.u.f 2 H h h h d d d d d d d d p C 7 ~.~.~.~.~.", +"~.~.~.~.~.C a d h h h h h g g z z z J J I I I I J P J.!.!.!.!.d.P =.e.G.E.!.!.!.!.Q.Z.f 2 z h h d d d d d d d d d d A ~.~.~.~.~.", +"~.~.~.~.~.A a h h h h h g z z z J H I I I I ^ / d X.E.!.!.!.Q.1.4 I J I ;.U.!.!.!.!.!.N.1 h g h h d d d d d d d d a S ~.~.~.~.~.", +"~.~.~.~.6 C p d h h h z z J J J I I I I ^ ^ ^ _ a 3.Q.!.!.!.E.#.I . ._ 3 ] K.!.!.!.!.E.O., z h h h d d d d d d d p A + ~.~.~.~.", +"~.~.~.~.i B d d h h h g z J I I I I ^ ^ ^ / / _ h k.!.!.!.!.J.) } . .| .3 6.Q.!.!.!.Q.q.> z g h h d d d d d d d d B t ~.~.~.~.", +"~.~.~.~.B d d d d h h h z z J I I ^ / / / _ _ ^ ( I.!.!.!.Q.d.I . . .| .d 1.Q.!.!.!.Q.q.2 z h h h d d d d d d d d d B ~.~.~.~.", +"~.~.~.~.C a d d d d h h g z J H I ^ ^ / _ _ } J %.E.!.!.!.Q.;.4 _ } | } J f m.!.!.!.!.Q.;.2 J z g h h d d d d d d d a A ~.~.~.~.", +"~.~.~.~.C a d d d d h h h z z J I I ^ ^ / _ } z 6.Q.!.!.!.!.n.<.&.+.{ ) ] h.Q.!.!.!.!.R.~ d H z z h h h d d d d d d a A ~.~.~.~.", +"~.~.~.~.A a d d d d d h h g z z H I I ^ / _ _ z k.!.!.!.!.!.!.Q.E.I.F.F.T.Q.!.!.!.!.E.9.2 I J z z h h h d d d d d d d A ~.~.~.~.", +"~.~.~.~.S a d d d d d h h h z z J I I ^ ^ / I ( P.!.!.!.!.Q.Q.!.!.!.!.!.!.!.!.!.!.E.w.d J I I J z h h h d d d d d d d A ~.~.~.~.", +"~.~.~.~.A a d d d d d d h h h z J J I I ^ / h O.E.!.!.!.Q.f.1.z.Y.E.!.!.!.!.!.!.L.! , ^ / I I H z z h h h d d d d d d A ~.~.~.~.", +"~.~.~.~.S p d d d d d d h h h z z J I I ^ / d <.Q.!.!.!.E.+.d _ +.>.k.E.!.!.!.!.Q.s.P J _ ^ I I J z z h h h d d d d d A ~.~.~.~.", +"~.~.~.~.C a d d d d d d d h h g z z H I I ^ d k.!.!.!.!.J.{ | @.} I I O.H.!.!.!.!.Q.C.l I ^ I I H J z g h h d d d d a A ~.~.~.~.", +"~.~.~.~.B a d d d d d d d h h h h z z J I J x P.!.!.!.Q.j.I . . . . .B { K.!.!.!.!.Q.0.a / ^ I I J z z h h h d d d a A ~.~.~.~.", +"~.~.~.~.B d d d d d d d d d h h h J h f 2 ; [ E.!.!.!.Q.1.I . . .| | .d 4.Q.!.!.!.!.m.z I ^ I I I J z h h h h d d d B ~.~.~.~.", +"~.~.~.~.u B d d d d d d d d h h z , ' v.q.X.M.!.!.!.!.E.#.^ . .| } } } d >.Q.!.!.!.!.F.x J I I I J J z z h h h d d C t ~.~.~.~.", +"~.~.~.~.7 C p d d d d d d d d h h : y.Q.Q.Q.!.!.!.!.!.B.d B / _ } } } J 1 k.!.!.!.!.!.c.s J I H J J z z z h h h h s A + ~.~.~.~.", +"~.~.~.~.~.A a d d d d d d d d h > ` R.!.!.!.!.!.!.!.!.L.q.=.[ ~ z h h l 0.Q.!.!.!.!.Q.q.2 I J J z z h h h h h h h a S ~.~.~.~.~.", +"~.~.~.~.~.C d d d d d d d d d d > ..g.Y.E.Q.!.!.!.!.!.!.Q.E.T.B.k.a.d.P.Q.!.!.!.!.!.E.[ 2 J z z z g h h h h d d d d C ~.~.~.~.~.", +"~.~.~.~.~.y C p d d d d d d d d g 3 > l [ <.x.W.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.Q.z.> z z z h h h h h d d d d p C 7 ~.~.~.~.~.", +"~.~.~.~.~.~.S a d d d d d d d d d h h 3 , > ; =.Q.!.W.T.Q.!.!.!.!.!.!.!.!.!.!.!.Q.A.g 2 z h h h h h h d d d d d a S ~.~.~.~.~.~.", +"~.~.~.~.~.~.C h s d d d d d d d d d h g z H : <.!.!.t.l &.V.!.!.Q.Q.Q.Q.!.Q.Q.E.b.l > H h h h h h d d d d d d s m C ~.~.~.~.~.~.", +"~.~.~.~.~.~.X S a d d d d d d d d d h h h h p N.!.Q.=.: < c.!.Q.2.&.e.a.d.i.6.[ < 2 z h h h h d d d d d d d d a S ~.~.~.~.~.~.", +"~.~.~.~.~.~.~.A h s d d d d d d d d d h g 2 ~ E.!.E.{ 2 [ E.!.T.l : 2 1 3 2 > > h z h h h h d d d d d d d d s m A ~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.S a d d d d d d d d d h h : -.R.!.B.h 2 =.Q.!.M.p z z z h h z g h h h d d d d d d d d d d d a S ~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.N C p d d d d d d d d d h 3 ' 2.N.9.2 3 z.!.!.q.> J z h h h h h h d d d d d d d d d d d d p C n ~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.S h p d d d d d d d d d z 3 : p l J g 8.T.S.O.> z h h h h h d d d d d d d d d d d d d p h S ~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.S a s d d d d d d d d h h z d h I J a P o.P d g h h h d d d d d d d d d d d d d d s a S ~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.* S a s d d d d d d d d h h g z J J h 3 > d z h h h d d d d d d d d d d d d d d s a S * ~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.$ T a s d d d d d d d h h h z z z h g g h h d d d d d d d d d d d d d d d d s a T O ~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.& S a p d d d d d d h h h z g h h h h h d d d d d d d d d d d d d d d d p a S # ~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.8 S d p d d d d d d h h g h h h h d d d d d d d d d d d d d d d d d p h S = ~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.S A a s d d d d h h h h h d d d d d d d d d d d d d d d d d s a A S ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.0 T m p d d d d h h h d d d d d d d d d d d d d d d d d p B S 9 ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.V S m a p d h d d d d d d d d d d d d d d d d p a m S V ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.o V S C d p p d d d d d d d d d d d d p p d C S N . ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.5 C S A B d d a a d d a a a d B A S C 5 ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.O t B A A A A A A A A B t O ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~." +}; diff --git a/share/pixmaps/bitcoin80.xpm b/share/pixmaps/bitcoin80.xpm deleted file mode 100644 index c3c816e9..00000000 --- a/share/pixmaps/bitcoin80.xpm +++ /dev/null @@ -1,292 +0,0 @@ -/* XPM */ -static const char * bitcoin80_xpm[] = { -/* columns rows colors chars-per-pixel */ -"80 80 206 2", -" c #725203", -". c #785706", -"X c #7B5907", -"o c #7C5A09", -"O c #7F5F10", -"+ c #815E0B", -"@ c #85620C", -"# c #89650F", -"$ c #856313", -"% c #896614", -"& c #8D6913", -"* c #886718", -"= c #8D6B1B", -"- c #926D14", -"; c #926E1B", -": c #967116", -"> c #997317", -", c #95711E", -"< c #9B7419", -"1 c #9F781B", -"2 c #A27B1D", -"3 c #8F6F22", -"4 c #926F21", -"5 c #947323", -"6 c #9A7623", -"7 c #9D7925", -"8 c #957628", -"9 c #9A7729", -"0 c #9D7B2B", -"q c #9D7F33", -"w c #A47D23", -"e c #A97F27", -"r c #A37E2B", -"t c #9F8030", -"y c #A78021", -"u c #AC8425", -"i c #A5802D", -"p c #AC842B", -"a c #AF8829", -"s c #B2872C", -"d c #B28B2D", -"f c #A68333", -"g c #AA8633", -"h c #AD8A36", -"j c #A4863A", -"k c #A88638", -"l c #A7893B", -"z c #AC8B3B", -"x c #B28732", -"c c #B48C32", -"v c #B98E34", -"b c #B28D3B", -"n c #B88F3C", -"m c #B69033", -"M c #BD9235", -"N c #B4913D", -"B c #BC943A", -"V c #BE993C", -"C c #C19336", -"Z c #C1953B", -"A c #C49A3C", -"S c #C99C3D", -"D c #CDA13F", -"F c #D0A33F", -"G c #A88B40", -"H c #B08F40", -"J c #AE9142", -"K c #AE944C", -"L c #B49443", -"P c #BB9542", -"I c #B49946", -"U c #BD9846", -"Y c #B3964C", -"T c #BB974A", -"R c #B6994A", -"E c #BF9C4A", -"W c #B69B53", -"Q c #B99D53", -"! c #BCA055", -"~ c #BDA25A", -"^ c #C49742", -"/ c #C49C43", -"( c #CB9E42", -") c #C49D4B", -"_ c #C99E4C", -"` c #C29F52", -"' c #C5A244", -"] c #CDA245", -"[ c #C5A34C", -"{ c #CCA34B", -"} c #CCA94D", -"| c #D2A445", -" . c #D1A54B", -".. c #D5AA4E", -"X. c #DBAF4F", -"o. c #C6A352", -"O. c #CBA554", -"+. c #C5AA57", -"@. c #CEAC54", -"#. c #C4A65A", -"$. c #CDA458", -"%. c #C2A85F", -"&. c #CEAA5B", -"*. c #D0A550", -"=. c #D4AB53", -"-. c #DBAE53", -";. c #D0A75B", -":. c #D4AC5A", -">. c #D9AE5C", -",. c #CEB25E", -"<. c #D4B156", -"1. c #DDB156", -"2. c #D4B25C", -"3. c #DCB35D", -"4. c #D7B85C", -"5. c #DCBA5E", -"6. c #E2B355", -"7. c #E2B65B", -"8. c #E4BA5D", -"9. c #EABD5E", -"0. c #C5AA62", -"q. c #CCAE63", -"w. c #C6AE69", -"e. c #D5AF62", -"r. c #CEB167", -"t. c #CCB36C", -"y. c #D5B162", -"u. c #DCB462", -"i. c #D7B964", -"p. c #DCBC64", -"a. c #D2B66B", -"s. c #DCB669", -"d. c #D7BE69", -"f. c #DFB86A", -"g. c #D0B771", -"h. c #D2BA74", -"j. c #D5BE78", -"k. c #E1B766", -"l. c #E4BB63", -"z. c #E9BE63", -"x. c #E3BB6A", -"c. c #E9BF6A", -"v. c #E1BE72", -"b. c #DDC16B", -"n. c #DAC27E", -"m. c #E4C164", -"M. c #ECC264", -"N. c #E4C36B", -"B. c #EBC36C", -"V. c #E7C96F", -"C. c #EECA6E", -"Z. c #F1C564", -"A. c #F1C76A", -"S. c #F5CB6C", -"D. c #FACE6D", -"F. c #F4D06F", -"G. c #FCD06E", -"H. c #E5C371", -"J. c #EDC573", -"K. c #E4CA73", -"L. c #ECCC74", -"P. c #E7CF7A", -"I. c #EBCD7A", -"U. c #F3CD73", -"Y. c #F8CE71", -"T. c #F3CD7A", -"R. c #EDD076", -"E. c #EDD17B", -"W. c #F4D274", -"Q. c #FBD274", -"!. c #FED977", -"~. c #F3D47B", -"^. c #FDD47A", -"/. c #F5DA7C", -"(. c #FDDA7C", -"). c #FFE07F", -"_. c #DBC481", -"`. c #DFC885", -"'. c #E1CA86", -"]. c #EACC80", -"[. c #E4CD8A", -"{. c #EED383", -"}. c #E7D18F", -"|. c #EAD38C", -" X c #F4D680", -".X c #FDD780", -"XX c #F5DA83", -"oX c #FCDC84", -"OX c #F5DB8A", -"+X c #FADE89", -"@X c #EAD492", -"#X c #EED896", -"$X c #EFDA9A", -"%X c #F1DD9D", -"&X c #FDE283", -"*X c #F6E18D", -"=X c #FEE48D", -"-X c #FFE692", -";X c #FFE894", -":X c #FBE799", -">X c #FFEA98", -",X c #F6E2A3", -".J..X.X.X.X(.W.Z.C.&X;X;X;X;X-X-X-X<.u u < 3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3Xu u c oX=X=X=X=X=X=X=Xl.Z C M M C C v v v s w = '.2X2X2X5 $ = 2X2X2X}.5 g ) u./.+X+X=X=X=X&XW.Z.F.=X;X;X;X;X-X-X*XV u y @ X 3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3Xu u u N.-X-X-X-X=X=X=XB.Z M C v v s e e e e w > % `.2X2X2X= + % 2X2X2X}.= r L 4.E.OX+X-X=X=X&X).W.M.R.;X;X;X-X-X-X;XR.u u y 3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3Xu u U -X-X-X-X-X-X=XW.^ C C C x e e r 6 5 4 ; = $ `.2X2X2X= O = 2X2X2X}.O = t Q ,.b.P./.*X=X&X&X).F.M.W.;X;X;X;X&X-X&X} u u O 3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3Xu u u R.-X-X-X-X-X-X=X=.{ ^ Z C x n 2X2X.>.>.=.=._ n b 2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X:XI N +.V./.).).F.F.9.W.;X=X;X-X-X-XR.u u > 3X3X3X3X3X3X3X3X", -"3X3X3X3X3Xu u d =X;X-X-X-X-X-Xx.>.>.>.>.>...^ P 2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X,Xl N 4.R.!.!.!.G.Z.M.&X;X=X=X-X-X-XB a u 3X3X3X3X3X3X3X", -"3X3X3X3X3Xu u @.;X;X-X;X;X;XXX>.:.>.>.>.>.>._ P ` Y Y W _.2X2X2X2X2X2X@XW W ~ 0.t.'..>.>.>.>.>.>.=._ P z r 4 8 2X2X2X2X2X2X_.. $ , 6 1 3 t ~ 1X2X2X2X2X2X2X2Xt B 5.G.!.!.G.G.M.9.&X;X=X-X-X=X/.u u > 3X3X3X3X3X3X3X", -"3X3X3X3Xu u d =X;X;X=X;X;X=X3.>.>.>.e.>.3.3.>.:.*._ P r 9 2X2X2X2X2X1Xn.@ , c B N m h 8 ~ 2X2X2X2X2X2X2XI h <.F.!.G.G.F.M.9.W.;X=X-X-X=X=Xm u y . 3X3X3X3X3X3X", -"3X3X3X3Xu u ' -X-X>X-X-X-X X>.>.>.>.>.>.>.u.u.u.u.3.$.P f 2X2X2X2X2X2X_.$ i / -.<.8.} h 8 1X2X2X2X2X2X2X! i <.S.G.G.G.G.Z.9.Z.=X-X=X-X&X-X} u u X 3X3X3X3X3X3X", -"3X3X3X3Xu u 4.-X-X-X-X-X-XJ.3.>.>.k.k.k.k.k.u.k.u.u.:.U k 2X2X2X2X2X1X_.% f } 8.Z.F.8.U 8 ,X2X2X2X2X2X2XI g } Z.D.G.D.G.D.Z.9.&X-X=X=X=X-Xm.u u @ 3X3X3X3X3X3X", -"3X3X3X3Xu u K.;X-X;X-X>X-Xk.3.k.k.k.k.k.k.k.k.k.k.u.e.U k 2X2X2X2X2X2X_.% f [ 8.F.M.<.b i 2X2X2X2X2X2X2Xt a X.Z.D.D.D.G.G.Z.9./.=X-X=X=X=XR.u u & 3X3X3X3X3X3X", -"3X3X3X3Xu u E.;X-X;X-X-X=Xl.l.x.c.k.x.k.k.x.x.v.x.x.u.) z 2X2X2X2X2X2X_.$ 7 L <.<.} N 6 h.2X2X2X2X2X2X_.: V 1.S.D.D.G.D.S.M.6.W.-X=X-X=X=X&Xu u > X 3X3X3X3X3X", -"3X3X3Xu a u =X;X;X;X;X;XoX7.z.c.c.c.c.c.c.c.c.c.x.k.u.) z 2X2X2X2X2X2Xn.o = i N h i l n.2X2X2X2X2X2X.o.L r [.2X2X2X9 = 8 2X2X2X}.4 r ^ _ *.*._ ) ) ^ ^ ^ O.oX=X-X-X-X-X-X-X<.u u : . 3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3Xy u u i.=X=X=X=X=X-X*X=XW.9.M.A.B.3.5.5.;.U f [.2X2X2Xq 4 8 2X2X2X}.r q _ _ ;.;.*._ _ ` _ e.+X-X-X-X-X-X-X-XR.a u 2 3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3Xu u u K.=X=X=X-X=X=X=X=XXXz.M.8.5.8.u.:.) h }.2X2X2Xj r f 2X2X2X@Xq T _ e.e.u.e.;.$.$.b.-X-X-X=X;X=X;X-X&Xa a u + 3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3Xu u d ~.=X=X=X=X=X-X=X-X+XC.3.5.7.7.2.@.) q.r.q.q.H H L g.r.w.q.T ` e.k.v.k.k.s.s.{.-X-X;X-X;X;X;X;X*XV u u & . 3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X2 u u c XX-X=X=X=X=X-X=X-X-X Xl.7.7.u.2.$.o.[ [ o.O.$.&.&.` ` ` q.s.k.v.k.k.x.{.%X>X>X>X;X>X;X>X>X*XV u u > 3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X2 u u m ~.=X-X-X-X=X-X-X-X-X-X Xc.7.5.u.3.e.y.u.s.f.k.s.e.e.s.s.k.k.k.v. X:X>X>X>X>X>X>X;X>X>X*XV u u < 3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X2 u u d R.-X=X-X=X-X-X-X-X-X-X-X+XI.v.u.s.l.k.k.x.x.x.s.s.s.s.j.].+X>X>X>X>X>X:X>X>X>X>X>XOXV u u 1 3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X2 u u a p.-X-X-X;X;X;X-X-X-X:X-X-X-X-XOX XL.J.J.J.L.I.].OX:X>X-X>X>X-X>X>X>X>X>X>X>X>XK.a a u < 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X2 u u u @.=X;X;X>X;X-X-X>X-X-X-X-X;X-X-X-X-X-X>X>X-X>X-X>X>X>X>X;X>X>X>X-X>X-X-X:X<.u u u > 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X1 u u u m n.>X;X>X>X-X-X-X-X>X-X-X-X;X;X;X-X-X-X-X-X>X-X-X>X-X>X>X-X>X>X>X>XK.B u u u & 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3Xw u u u / {.>X>X-X-X-X-X-X-X-X-X-X-X;X-X-X;X:X-X-X>X-X:X>X;X;X>X;X;X{.[ u u u w + 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X2 u u u u ) K.-X-X-X-X:X-X-X-X-X-X-X-X-X-X-X-X-X>X-X-X-X-X-X-XE.[ u u u u - . 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X1 u u u u m 2.E.-X+X:X-X-X-X-X-X-X-X-X-X:X-X-X-X;X-XOXi.B u u u u 1 o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X> u u u u u v [ l.I.OX-X-X-X-X-X-X-X-X+XI.f.@.m u u u u u 1 + o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X& 2 u u u u u u u d B V V V V B d u u u u u u u y - . o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X+ - 1 u u u u u u u a u u u u u u u u 2 - o o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3Xo . X # - > 1 2 2 2 1 2 > - # o . o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3Xo o . o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X" -}; diff --git a/share/pixmaps/bitgem32.xpm b/share/pixmaps/bitgem32.xpm deleted file mode 100644 index c77277b7..00000000 --- a/share/pixmaps/bitgem32.xpm +++ /dev/null @@ -1,468 +0,0 @@ -/* XPM */ -static char * BottleCaps32_xpm[] = { -"32 32 433 2", -" c None", -". c #B28F63", -"+ c #C8A274", -"@ c #C69962", -"# c #C59963", -"$ c #C59861", -"% c #C8A478", -"& c #C39760", -"* c #C49863", -"= c #C49963", -"- c #C49862", -"; c #C39862", -"> c #C49A67", -", c #C09F77", -"' c #D5AD79", -") c #E3AB66", -"! c #D38019", -"~ c #D3801B", -"{ c #D3811C", -"] c #D3811B", -"^ c #D07A10", -"/ c #DD9D4E", -"( c #EECB9E", -"_ c #D78D30", -": c #D17D15", -"< c #D17B11", -"[ c #E0A051", -"} c #E0B37D", -"| c #B9966D", -"1 c #C29C6C", -"2 c #D7913A", -"3 c #E1A050", -"4 c #DD9A48", -"5 c #D17A0F", -"6 c #D3801A", -"7 c #D27D14", -"8 c #D48422", -"9 c #ECC28F", -"0 c #F6D7B1", -"a c #E6B271", -"b c #D17A10", -"c c #D88D30", -"d c #E2A65B", -"e c #D98F33", -"f c #CE9F65", -"g c #AF8F67", -"h c #D39B55", -"i c #D57F15", -"j c #D5892A", -"k c #E1A965", -"l c #D68A2D", -"m c #D17E17", -"n c #D3821F", -"o c #D3821E", -"p c #D2811C", -"q c #D07B11", -"r c #E3AF6E", -"s c #F2CFA6", -"t c #F1C999", -"u c #F0CCA0", -"v c #DA9643", -"w c #D07A11", -"x c #D38320", -"y c #D2811D", -"z c #D27F19", -"A c #E1A863", -"B c #DA9541", -"C c #D2790C", -"D c #D69645", -"E c #C3A178", -"F c #CA9E68", -"G c #D88C2E", -"H c #D27E17", -"I c #D07C14", -"J c #DC9D4E", -"K c #DFA359", -"L c #D17D16", -"M c #DA9844", -"N c #F0CEA2", -"O c #F0C897", -"P c #EDC089", -"Q c #F2CEA3", -"R c #E8BC85", -"S c #D2821F", -"T c #D07B12", -"U c #DB9846", -"V c #E0A55C", -"W c #D78622", -"X c #D09C5C", -"Y c #BC976C", -"Z c #D7984B", -"` c #D37F16", -" . c #D2811E", -".. c #D3831F", -"+. c #D9933C", -"@. c #D17C14", -"#. c #D48524", -"$. c #EAC18D", -"%. c #F2CDA1", -"&. c #EEC28C", -"*. c #EEC592", -"=. c #EFC490", -"-. c #F2D1A9", -";. c #DEA156", -">. c #D58829", -",. c #E1AA65", -"'. c #D78E33", -"). c #D17C13", -"!. c #D8933D", -"~. c #C69E6D", -"{. c #CF9D5F", -"]. c #D88621", -"^. c #D2801C", -"/. c #D38422", -"(. c #D9943D", -"_. c #E2AB66", -":. c #E3AD6B", -"<. c #F3D4AE", -"[. c #EEC490", -"}. c #EFC592", -"|. c #EFC593", -"1. c #EEC390", -"2. c #F1CB9D", -"3. c #EEC899", -"4. c #D68B2F", -"5. c #CF790E", -"6. c #DEA053", -"7. c #DEA256", -"8. c #D38321", -"9. c #D28220", -"0. c #D58118", -"a. c #D49C56", -"b. c #B5936A", -"c. c #C09259", -"d. c #D88D31", -"e. c #CF7609", -"f. c #CF780C", -"g. c #DD9D50", -"h. c #D78F35", -"i. c #EDC18B", -"j. c #EEC28D", -"k. c #EDC08A", -"l. c #F2D0A7", -"m. c #E1A862", -"n. c #D5882A", -"o. c #DEA35A", -"p. c #D07C15", -"q. c #CF7910", -"r. c #D07B13", -"s. c #CE770D", -"t. c #D58521", -"u. c #C7975B", -"v. c #B59166", -"w. c #E1B680", -"x. c #DC9740", -"y. c #DB9947", -"z. c #DB9847", -"A. c #D99540", -"B. c #DB9A48", -"C. c #E8BF8A", -"D. c #EECEA4", -"E. c #F5D9B7", -"F. c #F3D1A8", -"G. c #F3D3AB", -"H. c #F3D2AB", -"I. c #F3D3AC", -"J. c #F4D4AE", -"K. c #F5DDC0", -"L. c #EDC38E", -"M. c #E6AB60", -"N. c #DF9841", -"O. c #E19D48", -"P. c #E19D49", -"Q. c #E29D48", -"R. c #E29D49", -"S. c #E39A41", -"T. c #E7B270", -"U. c #C09C72", -"V. c #B38E62", -"W. c #EDD1AD", -"X. c #F1CA9B", -"Y. c #EEC99B", -"Z. c #EFC99B", -"`. c #EFC99A", -" + c #EFC89A", -".+ c #EEC89A", -"++ c #EEC898", -"@+ c #EEC696", -"#+ c #F2D5B1", -"$+ c #ECC89B", -"%+ c #E1A964", -"&+ c #E2AC68", -"*+ c #E3AD6A", -"=+ c #E4AD68", -"-+ c #E9BB83", -";+ c #D1B594", -">+ c #B18349", -",+ c #B38449", -"'+ c #B4864D", -")+ c #B4864E", -"!+ c #B5864D", -"~+ c #B6864D", -"{+ c #B6874E", -"]+ c #B38348", -"^+ c #C1945E", -"/+ c #C7A984", -"(+ c #C8A67D", -"_+ c #F3CFA3", -":+ c #F0C48F", -"<+ c #F0C693", -"[+ c #F0CA9B", -"}+ c #E2AC6A", -"|+ c #CE7507", -"1+ c #CF780D", -"2+ c #CF790F", -"3+ c #CF780E", -"4+ c #D27A0D", -"5+ c #DA953E", -"6+ c #96682F", -"7+ c #764205", -"8+ c #7A4606", -"9+ c #7B4707", -"0+ c #7B4708", -"a+ c #794404", -"b+ c #7B4607", -"c+ c #A37D50", -"d+ c #D7B790", -"e+ c #F5CD9D", -"f+ c #EEC28E", -"g+ c #EEC491", -"h+ c #EEC38F", -"i+ c #F2CFA4", -"j+ c #EBC28F", -"k+ c #D7841F", -"l+ c #DAA665", -"m+ c #8E5E24", -"n+ c #7F4B0B", -"o+ c #865213", -"p+ c #804A08", -"q+ c #A27946", -"r+ c #C2A47E", -"s+ c #B39066", -"t+ c #E6C49B", -"u+ c #F3C894", -"v+ c #F2CCA0", -"w+ c #EDC697", -"x+ c #D5892B", -"y+ c #D17F19", -"z+ c #D3811E", -"A+ c #D6821B", -"B+ c #CA9B61", -"C+ c #895B24", -"D+ c #804A0A", -"E+ c #855112", -"F+ c #845112", -"G+ c #7F4907", -"H+ c #94662F", -"I+ c #B9986F", -"J+ c #C5A57E", -"K+ c #F1C692", -"L+ c #EFC591", -"M+ c #F0C795", -"N+ c #EFC897", -"O+ c #DDA054", -"P+ c #DB8F30", -"Q+ c #B48851", -"R+ c #83531A", -"S+ c #824D0C", -"T+ c #845011", -"U+ c #814B0B", -"V+ c #885518", -"W+ c #B08C61", -"X+ c #D6B790", -"Y+ c #F3CB9A", -"Z+ c #F1CCA0", -"`+ c #D37F18", -" @ c #E1A255", -".@ c #A17138", -"+@ c #7C490A", -"@@ c #834E0E", -"#@ c #814C0C", -"$@ c #A47C4B", -"%@ c #C5A885", -"&@ c #AD8A5E", -"*@ c #E6C49C", -"=@ c #F2C894", -"-@ c #EFC491", -";@ c #EEC38E", -">@ c #E8BA81", -",@ c #D47F16", -"'@ c #D8A15E", -")@ c #966831", -"!@ c #7C4706", -"~@ c #804B0A", -"{@ c #976A33", -"]@ c #BD9D76", -"^@ c #C4A27B", -"/@ c #F0CCA1", -"(@ c #F1C691", -"_@ c #F1CC9F", -":@ c #EBC08D", -"<@ c #D58A2D", -"[@ c #D68219", -"}@ c #C89659", -"|@ c #8F642F", -"1@ c #7F4908", -"2@ c #814C0B", -"3@ c #89571A", -"4@ c #B28F64", -"5@ c #D5B58D", -"6@ c #F4CC9C", -"7@ c #EFC38F", -"8@ c #EEC797", -"9@ c #DC9B4C", -"0@ c #D17E18", -"a@ c #DE9437", -"b@ c #B8884D", -"c@ c #84541A", -"d@ c #824D0D", -"e@ c #834F0F", -"f@ c #A88152", -"g@ c #B08C60", -"h@ c #E3C29B", -"i@ c #F3C995", -"j@ c #F2D0A8", -"k@ c #E0A65E", -"l@ c #E1A152", -"m@ c #A97B42", -"n@ c #855113", -"o@ c #9B703B", -"p@ c #B99970", -"q@ c #C1A078", -"r@ c #EECBA1", -"s@ c #F1C591", -"t@ c #EEC18C", -"u@ c #E5B273", -"v@ c #D37D12", -"w@ c #D59B53", -"x@ c #9D7341", -"y@ c #7D4705", -"z@ c #865314", -"A@ c #814B0A", -"B@ c #8D5D22", -"C@ c #B49268", -"D@ c #D2B38C", -"E@ c #F2CC9C", -"F@ c #F1CA9C", -"G@ c #EABD87", -"H@ c #D17F18", -"I@ c #D1811D", -"J@ c #D8851D", -"K@ c #C89250", -"L@ c #906735", -"M@ c #814B09", -"N@ c #834E0F", -"O@ c #AA8456", -"P@ c #AA875C", -"Q@ c #E2C199", -"R@ c #F3CA97", -"S@ c #DA9743", -"T@ c #D07C16", -"U@ c #DF973C", -"V@ c #BC8C50", -"W@ c #804F13", -"X@ c #844F0F", -"Y@ c #9E7441", -"Z@ c #BD9D77", -"`@ c #C09F78", -" # c #EDCAA0", -".# c #F3D4AF", -"+# c #DD9E4F", -"@# c #DD9A47", -"## c #B08550", -"$# c #7B4504", -"%# c #905F26", -"&# c #B7956D", -"*# c #D1B28C", -"=# c #EFC38D", -"-# c #F3D3AD", -";# c #E2AA65", -"># c #D27B10", -",# c #D39344", -"'# c #A37D4E", -")# c #7B4402", -"!# c #865315", -"~# c #AE895D", -"{# c #E1C19B", -"]# c #F3C996", -"^# c #F0C898", -"/# c #E9BB82", -"(# c #D48627", -"_# c #D7831B", -":# c #CD944D", -"<# c #906530", -"[# c #7D4604", -"}# c #A17948", -"|# c #BB9A72", -"1# c #BF9E75", -"2# c #EDCBA1", -"3# c #EEC99C", -"4# c #D58A2C", -"5# c #DB8C2A", -"6# c #C6965B", -"7# c #7A4504", -"8# c #92642B", -"9# c #B6946B", -"0# c #CFAF89", -"a# c #F2CC9E", -"b# c #F2D3AD", -"c# c #DA9239", -"d# c #D68A2B", -"e# c #B48A57", -"f# c #814E10", -"g# c #DEBF98", -"h# c #F7D6AD", -"i# c #E2A457", -"j# c #D28C36", -"k# c #A07948", -"l# c #BA9A70", -"m# c #EACAA1", -"n# c #F4C58B", -"o# c #CE944D", -"p# c #9E7542", -"q# c #B4936A", -"r# c #D0B28C", -"s# c #F4D4AD", -"t# c #D3A975", -"u# c #AC875B", -"v# c #E5D2BB", -"w# c #E0CAAE", -"x# c #AE895C", -"y# c #BB9D78", -"z# c #C5A989", -" . + @ # # # # # # $ # % & * * = * * - ; > , ", -" ' ) ! ~ { { { { ] ^ / ( _ : { { { { { < [ } | ", -" 1 2 3 4 5 { 6 6 6 7 8 9 0 a b ! 6 6 ] 7 c d e f ", -" g h i j k l m n o p q r s t u v w x o y z A B C D E ", -" F G H I J K L y x ^ M N O P Q R S z x T U V y m W X ", -" Y Z ` .p ..A +.@.m #.$.%.&.*.=.-.;.^ L >.,.'.: x ).!.~. ", -" {.].^.x /.L (._.x ^ :.<.[.}.|.1.2.3.4.5.6.7.L 8.x 9.0.a.b. ", -" c.d.e.I T T T f.g.h.+.u }.i.j.&.j.k.l.m.n.o.p.q.I r.I s.t.u. ", -"v.w.x.y.y.z.U U A.B.C.D.E.F.G.H.H.I.H.J.K.L.M.N.O.P.O.Q.R.S.T.U.", -"V.W.X.Y.Z.`. +.+++@+#+$+%+&+*+*+*+:.:.=+-+;+>+,+'+)+!+~+{+]+^+/+", -" (+_+:+}.}.}.}.}.<+[+}+|+1+2+2+2+2+3+4+5+6+7+8+9+9+0+0+a+b+c+ ", -" d+e+f+*.g+g+g+h+i+j+m y ........o k+l+m+n+o+o+o+o+o+p+q+r+ ", -" s+t+u+1.}.g+g+h+v+w+x+y+o z+y y { A+B+C+D+E+F+E+E+G+H+I+ ", -" J+u K+g+}.L+g+M+N+O+: o o o o 6 P+Q+R+S+F+T+E+U+V+W+ ", -" X+Y+=.g+g+}.=.Z+r w o y o o `+ @.@+@T+T+E+@@#@$@%@ ", -" &@*@=@-@*.}.;@F.>@T o o y o ,@'@)@!@E+E+T+~@{@]@ ", -" ^@/@(@g+L+h+_@:@<@z o o .[@}@|@1@T+E+2@3@4@ ", -" 5@6@7@}.g+L+8@9@r.x o 0@a@b@c@d@E+e@2@f@ ", -" g@h@i@1.}.j.j@k@5.8...).l@m@!@T+n@G+o@p@ ", -" q@r@s@g+t@<.u@@.n 9.v@w@x@y@z@A@B@C@ ", -" D@E@;@1.F@G@4.H@I@J@K@L@M@N@T+O@ ", -" P@Q@R@1.-@Y.S@r.T@U@V@W@X@A@Y@Z@ ", -" `@ #=@j..#+#2+T @###$#2@%#&# ", -" *#X.=#-#;#0@>#,#'#)#!#~# ", -" {#]#^#/#(#_#:#<#[#}#|# ", -" 1#2#=@3#4#5#6#7#8#9# ", -" 0#a#b#c#d#e#f#g@ ", -" g#h#i#j#}#k#l# ", -" ]@m#n#o#p#q# ", -" r#s#t#u# ", -" v#w#x# ", -" y#z# "}; diff --git a/share/pixmaps/bitgem80.xpm b/share/pixmaps/bitgem80.xpm deleted file mode 100644 index 1a0bad2b..00000000 --- a/share/pixmaps/bitgem80.xpm +++ /dev/null @@ -1,955 +0,0 @@ -/* XPM */ -static char * BottleCaps80_xpm[] = { -"81 80 872 2", -" c None", -". c #844E0D", -"+ c #8B5A1E", -"@ c #8A591D", -"# c #8A571A", -"$ c #895517", -"% c #895617", -"& c #895618", -"* c #885414", -"= c #885312", -"- c #885313", -"; c #885210", -"> c #87500D", -", c #824C0D", -"' c #824D0D", -") c #814B0A", -"! c #814A07", -"~ c #814A08", -"{ c #804904", -"] c #804702", -"^ c #7F4600", -"/ c #7E4400", -"( c #7F4400", -"_ c #7D4200", -": c #8B5513", -"< c #824A07", -"[ c #CFB89B", -"} c #FFF8ED", -"| c #FCF0DF", -"1 c #FCF0E0", -"2 c #FDF1E1", -"3 c #FDF2E3", -"4 c #FDF2E2", -"5 c #FDF1E2", -"6 c #FDF3E4", -"7 c #FDF3E6", -"8 c #FDF3E5", -"9 c #FEF4E7", -"0 c #FEF5E9", -"a c #FBEDDB", -"b c #FEF7ED", -"c c #FEF6EC", -"d c #FFF7ED", -"e c #FFF8EF", -"f c #FFF9F0", -"g c #FFFAF2", -"h c #FFFBF3", -"i c #FFFCF5", -"j c #FFFBF4", -"k c #FFFFFF", -"l c #AA8353", -"m c #94652C", -"n c #F2D8B9", -"o c #CD7303", -"p c #D17C13", -"q c #D07C13", -"r c #D17C14", -"s c #D27B11", -"t c #FBF3E9", -"u c #D17A0F", -"v c #D17D15", -"w c #D17D16", -"x c #D17E16", -"y c #D17E17", -"z c #D17C12", -"A c #FBF4EC", -"B c #FDFBF8", -"C c #88510F", -"D c #7F4703", -"E c #F6F3F0", -"F c #D78D32", -"G c #F7EAD8", -"H c #E0A45B", -"I c #D17E18", -"J c #D2811D", -"K c #D3821E", -"L c #D3821D", -"M c #D3811E", -"N c #D2811E", -"O c #D2821E", -"P c #D07A0F", -"Q c #EFD1AB", -"R c #FEFDFA", -"S c #EDCA9E", -"T c #D3811D", -"U c #D2821D", -"V c #D07A10", -"W c #F1D6B4", -"X c #E6B77C", -"Y c #E6B478", -"Z c #CDB9A0", -"` c #884F0B", -" . c #B99C79", -".. c #F4D8B4", -"+. c #D0790F", -"@. c #D78B2D", -"#. c #D0790E", -"$. c #D17D17", -"%. c #DC9B4A", -"&. c #FEFDFB", -"*. c #EDBD84", -"=. c #D78A2D", -"-. c #D2801B", -";. c #D27F19", -">. c #DA953F", -",. c #FCF7F0", -"'. c #D07B12", -"). c #FFFFFA", -"!. c #946327", -"~. c #895514", -"{. c #D27F18", -"]. c #D3821F", -"^. c #D07C14", -"/. c #EBC493", -"(. c #EECDA3", -"_. c #CF780D", -":. c #FDFCFA", -"<. c #F0C99B", -"[. c #EEC490", -"}. c #F2D0A9", -"|. c #F7EAD9", -"1. c #CF7609", -"2. c #CF770A", -"3. c #FDF8F2", -"4. c #DB9641", -"5. c #D17F19", -"6. c #DC9947", -"7. c #EDE8E0", -"8. c #814700", -"9. c #7F4601", -"0. c #E6DDD1", -"a. c #E1A861", -"b. c #D78D31", -"c. c #D27F1A", -"d. c #F0D4B0", -"e. c #F6E1C6", -"f. c #EEC28D", -"g. c #EFC592", -"h. c #EDC18A", -"i. c #FCF5EC", -"j. c #E2AA65", -"k. c #E8BC86", -"l. c #FAE3C6", -"m. c #AE8A5F", -"n. c #8E5918", -"o. c #A67F4E", -"p. c #FDEDD8", -"q. c #CF790F", -"r. c #DD9C4C", -"s. c #FAF2E6", -"t. c #CF770B", -"u. c #D38320", -"v. c #DD9E4D", -"w. c #FEFDFC", -"x. c #EDC089", -"y. c #EEC592", -"z. c #FEFEFC", -"A. c #D2801A", -"B. c #D2811C", -"C. c #D48421", -"D. c #D27E17", -"E. c #D38321", -"F. c #D3811C", -"G. c #834D0C", -"H. c #D58523", -"I. c #CF780C", -"J. c #F4DEC4", -"K. c #E5B476", -"L. c #EFC797", -"M. c #EEC491", -"N. c #EFC591", -"O. c #EEC38E", -"P. c #F7E0C7", -"Q. c #EFD2AD", -"R. c #F6E5D1", -"S. c #E1A964", -"T. c #EBBC82", -"U. c #D1BFA8", -"V. c #834B06", -"W. c #834C09", -"X. c #D1BEA6", -"Y. c #CF790E", -"Z. c #D4821E", -"`. c #F1D7B6", -" + c #F6DFC4", -".+ c #DA943D", -"++ c #DFA45A", -"@+ c #F9EDDD", -"#+ c #FFFBF1", -"$+ c #986A32", -"%+ c #986B33", -"&+ c #E4B071", -"*+ c #F4DFC4", -"=+ c #D2801C", -"-+ c #DFA255", -";+ c #FFFCFA", -">+ c #EDC088", -",+ c #EFC491", -"'+ c #F2CFA5", -")+ c #FAF2E7", -"!+ c #D27E16", -"~+ c #D58828", -"{+ c #DC9740", -"]+ c #F2EFEA", -"^+ c #814904", -"/+ c #804906", -"(+ c #F6F3EF", -"_+ c #DB943D", -":+ c #CF780B", -"<+ c #FBF2E8", -"[+ c #DD9C4B", -"}+ c #D3801B", -"|+ c #EFC693", -"1+ c #EFC593", -"2+ c #EDBF88", -"3+ c #FBF3E8", -"4+ c #E5B374", -"5+ c #EECEA7", -"6+ c #EAC290", -"7+ c #F7DBB9", -"8+ c #B5956D", -"9+ c #89520E", -"0+ c #844C08", -"a+ c #BB9F7B", -"b+ c #F4D6B1", -"c+ c #D88E33", -"d+ c #D0790D", -"e+ c #F1D8B8", -"f+ c #F7E0C5", -"g+ c #EEC38F", -"h+ c #EEC591", -"i+ c #D37F18", -"j+ c #D88D32", -"k+ c #FEFCF8", -"l+ c #844D0B", -"m+ c #EECEA5", -"n+ c #EAC292", -"o+ c #DFA256", -"p+ c #FEFCF9", -"q+ c #F6DFC3", -"r+ c #F0D4B1", -"s+ c #FBF5EC", -"t+ c #DC9A48", -"u+ c #E7B476", -"v+ c #D8CAB8", -"w+ c #804500", -"x+ c #7E4500", -"y+ c #E4DCD1", -"z+ c #E2A861", -"A+ c #D17F18", -"B+ c #D17B11", -"C+ c #D68A2B", -"D+ c #EFC897", -"E+ c #EFC492", -"F+ c #FFFFFE", -"G+ c #DA9540", -"H+ c #F3DDC1", -"I+ c #FFF9EE", -"J+ c #986B34", -"K+ c #8B5310", -"L+ c #A68153", -"M+ c #FEEDD8", -"N+ c #E0A359", -"O+ c #F9EDDF", -"P+ c #F2DABC", -"Q+ c #F6DEC2", -"R+ c #EEC28C", -"S+ c #EEC492", -"T+ c #F1CEA3", -"U+ c #D0770B", -"V+ c #D38019", -"W+ c #DA933D", -"X+ c #F5F4F1", -"Y+ c #7F4602", -"Z+ c #824B08", -"`+ c #D48625", -" @ c #F5E3CD", -".@ c #E2AC69", -"+@ c #E0A55C", -"@@ c #FEFBF8", -"#@ c #EDC18B", -"$@ c #FAEEDF", -"%@ c #E6B87F", -"&@ c #E5B274", -"*@ c #F6D8B4", -"=@ c #B99C78", -"-@ c #89510F", -";@ c #834C0A", -">@ c #D4C3AE", -",@ c #EABC84", -"'@ c #D48320", -")@ c #D28019", -"!@ c #EFC695", -"~@ c #DE9E50", -"{@ c #FAF0E4", -"]@ c #8A5516", -"^@ c #986931", -"/@ c #FFFCF3", -"(@ c #D07B13", -"_@ c #E7BA81", -":@ c #F3DDC2", -"<@ c #F5DCBD", -"[@ c #F4DAB9", -"}@ c #F3DCC0", -"|@ c #D07A11", -"1@ c #E3AD6A", -"2@ c #DFD2C2", -"3@ c #824B07", -"4@ c #814906", -"5@ c #F9F7F4", -"6@ c #D89138", -"7@ c #FDF8F3", -"8@ c #E0A760", -"9@ c #FEFAF5", -"0@ c #FFFDFC", -"a@ c #EBC698", -"b@ c #FFF6E7", -"c@ c #9E723D", -"d@ c #925E1E", -"e@ c #864F0C", -"f@ c #BC9F7B", -"g@ c #F5D6B1", -"h@ c #DA9641", -"i@ c #FCF7EF", -"j@ c #FEFEFE", -"k@ c #EFC694", -"l@ c #F0CA9C", -"m@ c #FBF5ED", -"n@ c #D0780D", -"o@ c #D68929", -"p@ c #D17D13", -"q@ c #D98F34", -"r@ c #FAFAF9", -"s@ c #7E4501", -"t@ c #905F23", -"u@ c #D17D14", -"v@ c #CE7304", -"w@ c #EFCEA5", -"x@ c #E6B679", -"y@ c #F1DABB", -"z@ c #F3D7B4", -"A@ c #EEC18B", -"B@ c #EEC18A", -"C@ c #EDC08A", -"D@ c #F8E9D4", -"E@ c #F5E5CF", -"F@ c #DB9845", -"G@ c #CF760A", -"H@ c #CD7201", -"I@ c #F1CC9E", -"J@ c #BDA07C", -"K@ c #824A06", -"L@ c #854F0D", -"M@ c #D2BB9E", -"N@ c #F9F0E4", -"O@ c #F9F1E6", -"P@ c #F9EFE3", -"Q@ c #F8EEDF", -"R@ c #F8ECDC", -"S@ c #F7EADA", -"T@ c #F6E8D6", -"U@ c #F6E6D3", -"V@ c #F6E7D3", -"W@ c #F6E6D2", -"X@ c #F6E5D0", -"Y@ c #FEFFFF", -"Z@ c #FCF6ED", -"`@ c #FCF6EE", -" # c #FCF5ED", -".# c #FCF5EB", -"+# c #FCF4EB", -"@# c #FCF4EA", -"## c #FCF4E9", -"$# c #FBF4E9", -"%# c #FBF3E7", -"&# c #FBF2E6", -"*# c #FBF1E5", -"=# c #FBF1E4", -"-# c #FBF0E3", -";# c #F2D3AC", -"># c #F4D9B6", -",# c #F4D7B1", -"'# c #F3D6B0", -")# c #F3D4AD", -"!# c #F3D4AC", -"~# c #F2D1A8", -"{# c #F1D1A8", -"]# c #F1CEA2", -"^# c #F0CC9E", -"/# c #F0CB9E", -"(# c #EFC899", -"_# c #F0C999", -":# c #EFC999", -"<# c #EEC694", -"[# c #EEC695", -"}# c #ECC089", -"|# c #A57B49", -"1# c #824C0B", -"2# c #F0C897", -"3# c #EFC796", -"4# c #F0C796", -"5# c #F0C898", -"6# c #F0C99A", -"7# c #F0CA9B", -"8# c #F1CB9E", -"9# c #F8E8D4", -"0# c #E8BE88", -"a# c #D78D33", -"b# c #D9923A", -"c# c #D9933C", -"d# c #D9943E", -"e# c #DA9642", -"f# c #DA9744", -"g# c #DB9846", -"h# c #DA9846", -"i# c #DB9A48", -"j# c #DC9A4A", -"k# c #DC9C4C", -"l# c #DC9D4E", -"m# c #DC9C4D", -"n# c #DD9E50", -"o# c #DD9F52", -"p# c #DD9F51", -"q# c #DDA155", -"r# c #DB9948", -"s# c #FCF1E3", -"t# c #B59064", -"u# c #A88150", -"v# c #A88050", -"w# c #A98353", -"x# c #AA8454", -"y# c #AA8354", -"z# c #AB865A", -"A# c #AB875B", -"B# c #AB895F", -"C# c #AC8A60", -"D# c #AB8960", -"E# c #B18D62", -"F# c #B39067", -"G# c #B3936D", -"H# c #B3946D", -"I# c #B49773", -"J# c #B49772", -"K# c #B39671", -"L# c #BE9F79", -"M# c #97652A", -"N# c #8C5717", -"O# c #9B6E37", -"P# c #F1CEA4", -"Q# c #F4E0C7", -"R# c #D07E17", -"S# c #804805", -"T# c #824D0C", -"U# c #824C0C", -"V# c #814C0C", -"W# c #814C0B", -"X# c #814B0B", -"Y# c #773C00", -"Z# c #EEE4D8", -"`# c #A8804E", -" $ c #C9B193", -".$ c #FCECD7", -"+$ c #D27D15", -"@$ c #D89139", -"#$ c #EAE1D5", -"$$ c #7A4200", -"%$ c #855112", -"&$ c #845011", -"*$ c #855011", -"=$ c #845012", -"-$ c #804A08", -";$ c #C4A884", -">$ c #D6C2A9", -",$ c #7E4602", -"'$ c #F1EDE5", -")$ c #F1CFA6", -"!$ c #FDFAF4", -"~$ c #D78F35", -"{$ c #ECC088", -"]$ c #BDA17E", -"^$ c #814D0D", -"/$ c #966830", -"($ c #FBF8F3", -"_$ c #864E09", -":$ c #946023", -"<$ c #8B591B", -"[$ c #EDC28E", -"}$ c #FBEEDF", -"|$ c #E2AA64", -"1$ c #976932", -"2$ c #865214", -"3$ c #855111", -"4$ c #845111", -"5$ c #845112", -"6$ c #855213", -"7$ c #804907", -"8$ c #97682E", -"9$ c #BA9A74", -"0$ c #FFF6E8", -"a$ c #F4D6B2", -"b$ c #EFD3B1", -"c$ c #F8F2EA", -"d$ c #885413", -"e$ c #7B4400", -"f$ c #DBC8B1", -"g$ c #C0A27D", -"h$ c #7D4501", -"i$ c #E8DED1", -"j$ c #F5D8B5", -"k$ c #FCF6F0", -"l$ c #D68F36", -"m$ c #EDE6DD", -"n$ c #7B4200", -"o$ c #855012", -"p$ c #A8804F", -"q$ c #EFE5DA", -"r$ c #814600", -"s$ c #865111", -"t$ c #FDF9F3", -"u$ c #D68A2C", -"v$ c #E7B372", -"w$ c #C6B095", -"x$ c #7F4A09", -"y$ c #844F10", -"z$ c #875212", -"A$ c #8E5919", -"B$ c #86500E", -"C$ c #FFFFF9", -"D$ c #EDBF87", -"E$ c #DEA156", -"F$ c #FBE6CC", -"G$ c #9A6E39", -"H$ c #865315", -"I$ c #7A4100", -"J$ c #F1E8DC", -"K$ c #AD8657", -"L$ c #7D4502", -"M$ c #D8C7B1", -"N$ c #FAE3C7", -"O$ c #EEC28E", -"P$ c #F5DDBF", -"Q$ c #ECC89A", -"R$ c #FBF7F0", -"S$ c #865213", -"T$ c #865314", -"U$ c #7E4705", -"V$ c #C0A27E", -"W$ c #D8C5AE", -"X$ c #F1CB9D", -"Y$ c #FAF1E4", -"Z$ c #D78F36", -"`$ c #ECE4DA", -" % c #7C4300", -".% c #95652B", -"+% c #FFFEFB", -"@% c #844C07", -"#% c #8C5716", -"$% c #9A6D37", -"%% c #E4AE6A", -"&% c #CDB9A1", -"*% c #7E4603", -"=% c #FDFAF6", -"-% c #9A6C34", -";% c #C8AF91", -">% c #FDEDD9", -",% c #DD9E51", -"'% c #F8DEBD", -")% c #A17847", -"!% c #7B4401", -"~% c #D9C5AE", -"{% c #C2A481", -"]% c #F7F3ED", -"^% c #EEC18C", -"/% c #F7E4CB", -"(% c #E8BC85", -"_% c #CF7608", -":% c #824E0E", -"<% c #F0E8DC", -"[% c #854C07", -"}% c #946021", -"|% c #916125", -"1% c #EDC18C", -"2% c #F1CDA2", -"3% c #F4E3CC", -"4% c #EEE7E0", -"5% c #7F4806", -"6% c #905D1E", -"7% c #87500F", -"8% c #B99973", -"9% c #FFF6E9", -"0% c #D0780C", -"a% c #E1A962", -"b% c #D4C2AC", -"c% c #7B4300", -"d% c #EFE5D8", -"e% c #AE885A", -"f% c #7D4400", -"g% c #E8DED2", -"h% c #F4D7B3", -"i% c #F3D2A9", -"j% c #AC885D", -"k% c #804A09", -"l% c #7F4908", -"m% c #BC9C76", -"n% c #DDCCB7", -"o% c #854B03", -"p% c #85500F", -"q% c #F8E6CF", -"r% c #E6B77E", -"s% c #845010", -"t% c #926125", -"u% c #854D09", -"v% c #864F0D", -"w% c #A98253", -"x% c #FFFEF6", -"y% c #F3D3AC", -"z% c #F2DABB", -"A% c #D5831E", -"B% c #F2EFEB", -"C% c #7E4806", -"D% c #7F4704", -"E% c #FEFBF6", -"F% c #9B6E36", -"G% c #7D4500", -"H% c #D8C7B2", -"I% c #F8E2C5", -"J% c #FDF9F4", -"K% c #E2A860", -"L% c #7D4603", -"M% c #7C4503", -"N% c #D5C0A6", -"O% c #C7AC8B", -"P% c #7E4704", -"Q% c #FBFBF9", -"R% c #F1CA9C", -"S% c #FEFCFA", -"T% c #D6892A", -"U% c #B29068", -"V% c #F4EDE4", -"W% c #9D713B", -"X% c #F9E9D6", -"Y% c #E2AE6C", -"Z% c #FFF3E2", -"`% c #8E5D20", -" & c #834E0F", -".& c #814B08", -"+& c #905D1F", -"@& c #CBB395", -"#& c #FEEED9", -"$& c #D27C13", -"%& c #FBFAF8", -"&& c #7C4502", -"*& c #855113", -"=& c #794000", -"-& c #E9DECE", -";& c #AF8C5F", -">& c #804905", -",& c #F6F2EC", -"'& c #F3D0A6", -")& c #EFC795", -"!& c #F9EFE1", -"~& c #E0A051", -"{& c #D9CBBA", -"]& c #BA9971", -"^& c #E0D0BC", -"/& c #844903", -"(& c #915F24", -"_& c #EDC08B", -":& c #D3801A", -"<& c #EFCA9A", -"[& c #B79872", -"}& c #8E5C1F", -"|& c #885110", -"1& c #B99972", -"2& c #FFF4E6", -"3& c #FAEFE1", -"4& c #DFA359", -"5& c #D07B11", -"6& c #FBEBD6", -"7& c #96672F", -"8& c #FBF8F2", -"9& c #9D7039", -"0& c #E8DFD2", -"a& c #EEC390", -"b& c #F4D9B8", -"c& c #EECDA4", -"d& c #D27D16", -"e& c #FFFEFA", -"f& c #D2BB9F", -"g& c #C9B091", -"h& c #854F0E", -"i& c #F7E9D8", -"j& c #DE9843", -"k& c #DFD5C8", -"l& c #7D4705", -"m& c #834F10", -"n& c #A17743", -"o& c #F8F3EC", -"p& c #834A04", -"q& c #874F0D", -"r& c #A88152", -"s& c #FFFCF4", -"t& c #D38421", -"u& c #B89A75", -"v& c #8E5A1C", -"w& c #7F4702", -"x& c #DCCCB8", -"y& c #F8E1C4", -"z& c #FDF7F0", -"A& c #DA943E", -"B& c #F9E6CE", -"C& c #9D713C", -"D& c #E7DBC9", -"E& c #B49066", -"F& c #824C0A", -"G& c #FDFDFB", -"H& c #F6DFC2", -"I& c #E9C08E", -"J& c #7F4807", -"K& c #B59268", -"L& c #E5D8C7", -"M& c #8D5513", -"N& c #9C703B", -"O& c #F1CDA1", -"P& c #D38422", -"Q& c #D98E31", -"R& c #EAE3DA", -"S& c #834E0E", -"T& c #8D5B1E", -"U& c #87510F", -"V& c #CAB295", -"W& c #FDECD7", -"X& c #FBF5EE", -"Y& c #D3831F", -"Z& c #EDBF85", -"`& c #BFA483", -" * c #FAF5EF", -".* c #A07540", -"+* c #F4F0EA", -"@* c #F3D1A7", -"#* c #D88F36", -"$* c #FBE8CE", -"%* c #9D723D", -"&* c #CEB698", -"** c #CCB598", -"=* c #844902", -"-* c #F8E5CE", -";* c #E6B67A", -">* c #FBF4EB", -",* c #875211", -"'* c #804B0A", -")* c #9F733E", -"!* c #FAF6EF", -"~* c #814802", -"{* c #B89872", -"]* c #F5E2CB", -"^* c #D68B30", -"/* c #F1EBE2", -"(* c #814B09", -"_* c #905F22", -":* c #7E4601", -"<* c #F3D6B2", -"[* c #E7B474", -"}* c #C6AF93", -"|* c #7D4704", -"1* c #E5D8C6", -"2* c #8B5719", -"3* c #EDC390", -"4* c #FEFAF6", -"5* c #FAE3C5", -"6* c #9F7643", -"7* c #804B0B", -"8* c #B18D61", -"9* c #E7DACA", -"0* c #8D5817", -"a* c #A98355", -"b* c #FFFEF7", -"c* c #FBEFE1", -"d* c #E1A760", -"e* c #FAF2E9", -"f* c #8C591B", -"g* c #8A5719", -"h* c #885211", -"i* c #804803", -"j* c #DBCBB7", -"k* c #F8DFC2", -"l* c #F4D5B1", -"m* c #D58A2E", -"n* c #F2ECE5", -"o* c #F9F3EB", -"p* c #A27845", -"q* c #FDFDFC", -"r* c #E3A861", -"s* c #CFBEA7", -"t* c #7D4604", -"u* c #CAB091", -"v* c #D1BCA0", -"w* c #824801", -"x* c #9C6F39", -"y* c #F8DDBA", -"z* c #A17A4A", -"A* c #FEFCF7", -"B* c #804703", -"C* c #814803", -"D* c #FBEAD4", -"E* c #DEA257", -"F* c #926024", -"G* c #F4EFEA", -"H* c #F5DDBE", -"I* c #ECC89C", -"J* c #D58A2C", -"K* c #EFE9E1", -"L* c #E2D3BF", -"M* c #BA9973", -"N* c #916024", -"O* c #D6C6B2", -"P* c #EADFD1", -"Q* c #86500D", -"R* c #BB9B75", -"S* c #FFF7E9", -"T* c #F3D1A6", -"U* c #AD8A60", -"V* c #834F0F", -"W* c #875312", -"X* c #895413", -"Y* c #EAE0D4", -"Z* c #FCF3E9", -"`* c #FFF9ED", -" = c #885619", -".= c #F4EDE3", -"+= c #A47C4A", -"@= c #8A5617", -"#= c #F7E4CA", -"$= c #D4831F", -"%= c #F2EEE8", -"&= c #C8AD8C", -"*= c #D4BFA5", -"== c #844B06", -"-= c #8E5716", -";= c #AB8456", -">= c #F5E4CE", -",= c #DBCDBB", -"'= c #FDFAF5", -")= c #844D0A", -"!= c #814905", -"~= c #F7DFC2", -"{= c #CE7506", -"]= c #EFC898", -"^= c #B69771", -"/= c #926227", -"(= c #FFF3E1", -"_= c #DECCB7", -":= c #BE9F7A", -"<= c #874F0B", -"[= c #9B6E38", -"}= c #FFFFF8", -"|= c #F7E1C8", -"1= c #E6B374", -"2= c #F3EEE6", -"3= c #A77E4D", -"4= c #F0E7DC", -"5= c #7D4300", -"6= c #804600", -"7= c #C9B092", -"8= c #E0CFBA", -"9= c #86510F", -"0= c #F4EEE6", -"a= c #A47B49", -"b= c #D2BCA1", -"c= c #8A5412", -"d= c #B28D61", -"e= c #875110", -" . + @ @ @ @ # $ % % % % & * = = = = = - ; > > > > > > . , ' ' ' ' ' ) ! ! ! ! ! ~ { ] ] ] ] ] ] ^ / ( ( _ : ", -" < [ } | 1 1 1 2 3 4 4 4 4 5 6 7 7 7 7 7 8 9 0 0 0 0 0 0 a b c c c c c d e e e e e e f g g g g g g h i i j k l ", -" m k n o p p q p p p p p p p r r r r r r r r r r r r p s t u v v v v v v w w w w w w w w w w w w w x y w z A B C ", -" D E F G H I J K L J J M K N O L K L K L J K K J O O K P Q R S P T K K O K T K K T K K K U U M U T J U K V W X Y Z ` ", -" C ...+.@.k #.O K T J N J K N J L J J K L N K M J N K $.%.&.*.k =.-.J M N K J K J J J J N J J N O J N U ;.>.,.P '.).!. ", -" ~.k {.].^./.(._.K T O K M K M O U K L K L K O K J O N P :.<.[.}.|.1.].M O K T O K T K K K U U M K T K K 2.3.4.5.O 6.7.8. ", -" 9.0.a.-.J J V &.b.c.J J T T T M J N T M T M J J M J K 2.d.e.f.g.h.i.j.5.J N K M J T M T T M N N M J T K V k.d.V K K V l.m. ", -" n.o.p.q.K K K -.r.s.t.u.J J J K J J L J J K L J K M J w v.w.x.y.g.g.y.z.A.].K K J K J J J J N J J N J J B.C.k D.J J J E.F.k ; ", -" G.k H.E.J K K K I.J.K.y J M N K M N K N J K K N K J u.p w.L.M.g.N.M.O.P.Q.+.K K J K N J N N M J J N O ].t.R.S.I K J K J V T.U.V. ", -" W.X.h.Y.T U U O K K F.k Z.u.K J U J J O J J L O J U K V `. +f.g.M.M.g.g.x.k .+J J J U J J J J J J J J J -.++@+2.K K J O J K t.#+$+ ", -" %+#+t.K J K K K K K y &+*+V T K K M K K K K K K N N =+-+;+>+g.,+M.,+g.M.y.'+)++.J K K K K K K K K K K u.!+k ~+K K K K K N K I {+]+^+ ", -" /+(+_+I K J K K K K L ].:+<+[+N T K N O L K L K L J K }+k |+1+M.M.M.M.g.g.g.2+3+4+I K K K T K K K U U J q 5+6+q K K K U L J K K I.7+8+9+ ", -" 0+a+b+V K J J K K K K L O u.c+w.d+K K N J L J J K L K I.e+f+g+M.,+,+M.,+g.M.g.M.h+k i+B.K J J J J N J K O j+k+p ].J N K J L J M J B.F.k l+ ", -" * k !+J K K K K K K K K K T q.m+n+'.K M O U K L K K I o+p+>+1+g.,+,+M.,+,+,+,+M.f.q+r+_.K K T K K K U K 2.s+t+O J K K K U L K N K T y u+v+w+ ", -" x+y+z+A+L T T J T T K L K T K K B+k C+=+K J N T M T J !+k D+[.M.E+E+M.M.M.E+E+,+,+g.x.F+G+I K M T T M K w 4+H+I.K T T M M N M J J L J J d+I+J+ ", -" K+L+M+t.K O J J J K K K K L J K K v N+O+2.K J L J J K I.P+Q+R+g.h+S+,+M.M.M.g.M.g.M.g.g+T+t U+K J J J N B.Z.k V+J J J J N K J L J M U J K B.W+X+Y+ ", -" Z+k `+J K K N N N K K K K K M K K K I. @.@v K K N K v +@@@2+g.M.h+S+N.N.M.N.g.h+g.M.g.g.#@$@%@V K N N K _.*+&@'.K M L K M K J K N K K O K K #.*@=@-@ ", -" ;@>@,@v K J U J J J U U O U K J K U J -.'@k D.J O J J )@k !@[.g.M.h+E+M.M.M.M.g.,+g.,+g.M.M.g+k K J N J I ~@{@2.K J J U U J K J O J U U J O L ].I k ]@ ", -" ^@/@I.K K J K K K N K K K K K K K K N K (@_@W +.K K I.:@<@f.g.g.M.g.E+g.,+M.,+g.g.g.E+g.g.g.g+[@}@I.K O |@&.b.c.O K M L K K K K K N K K O K T J A+1@2@3@ ", -" 4@5@6@O J K J K K K J K K K K L K K L J J O 2.7@4.A+v 8@9@2+g.N.g.M.y.g.g.M.M.M.g.g.N.N.g.h+g.g.>+0@t+O '.a@S +.K U T J U U K K U L J K K U K J J ].t.b@c@d@ ", -" e@f@g@q J J M J O J J J K K K K L J K T J N J B.h@i@d+A.j@k@g.M.g.g.M.h+M.,+,+M.,+g.M.g.M.g.M.g.M.g.l@m@n@o@k p@J J O J N U U N K J L J M U U K J J N u.q@r@s@ ", -" t@i #.{.v v u@r u@r r r p p p q p p '.'.'.'.'.'.v@w@x@y@z@x.A@A@A@A@A@A@A@A@B@h.h.h.h.h.C@C@C@C@x.x.*.D@Y E@F@G@_._._.Y.Y.Y.#.#.#.+.+.+.P P P V V V |@|@H@I@J@K@", -"L@M@k N@O@O@O@P@P@P@Q@Q@Q@R@R@R@|.S@|.T@T@T@U@V@W@X@W@k Y@Z@`@Z@Z@ #.#.#+#@#@###t $#3+%#%#&#&#&#*#=#*#=#-#k k ;#>#,#'#b+)#!#)#~#{#~#]#]#]#^#/#^#(#_#:#<#<#[#}#k |#", -" 1#B 2#,+[.[.g.g.g.k@k@k@3#4#4#5#5#5#6#6#6#l@7#l@8#6#9#0#a#6@b#b#c#d#d#>.e#e#f#g#h#i#j#j#k#l#m#n#o#p#q#r#s#t#u#v#w#x#y#z#A#A#B#C#D#E#E#E#F#F#F#G#G#H#I#J#K#L#k M#", -" N#O#k C@g.M.M.M.M.M.M.M.M.M.M.M.M.M.[.[.[.[.[.[.[.M.P#Q#1.-.A.A.A.A.A.A.A.A.c.c.c.c.;.c.;.;.;.;.;.;.-.R#s+S#T#T#U#U#U#V#V#V#V#V#V#W#W#W#W#W#W#W#W#W#X#T#Y#Z#`# ", -" /+ $.$R+M.g.M.N.N.h+M.g.g.g.g.g.S+g.g.,+g.M.g.,+g.y.,.+$K O J U K J J J J U J U O U U J U J O J U E.@$#$$$%$&$&$&$*$&$=$=$&$&$%$&$%$=$%$&$&$%$&$&$&$-$;$>$ ", -" ,$'$)$M.g.M.g.g.g.,+g.g.g.g.g.E+g.g.M.S+g.g.M.g.2+!$~$].K N K K N K K K K J K K K O K K K K K K A+{$]$^$%$%$%$%$*$%$=$=$&$%$%$%$%$=$%$%$&$%$&$&$%$/$($_$ ", -" :$<$k [$g.M.N.g.y.M.N.g.g.g.g.g.g.g.M.y.h+g.M.M.f.}$|$J L J K K J O O K U J U K U O K K O K T J t..$1$2$%$%$3$%$*$4$=$5$4$3$%$%$%$5$%$%$4$%$&$6$7$k 8$ ", -" ;@9$0$x.g.h+h+h+,+g.g.g.g.g.,+y.y.M.h+M.y.M.,+g.a$b$'.K N K M J N J J U J U M U K N M N K J K w c$d$%$4$4$&$4$*$4$=$5$4$&$%$4$%$5$%$4$4$%$%$e$f$g$ ", -" h$i$j$f.g.N.N.,+,+,+,+g.g.E+N.,+,+g.,+,+,+,+1+3#k$1.J K O K J O O K K J K M U O K M O K T ].l$m$n$%$%$%$*$%$o$4$o$%$5$*$%$%$5$%$5$%$&$%$X#p$q$r$ ", -" s$k g.M.g.y.M.,+E+E+g.g.E+y.S+M.S+M.S+M.E+g.A@t$u$J J J M J N J T T J T M O J M T N K M =+v$w$x$&$&$&$&$&$&$&$&$&$&$&$&$&$4$&$=$&$%$y$z$k A$ ", -" B$w#C$D$g.h+M.g.g.g.g.g.E+g.g.M.S+M.g.M.,+M.>+&#E$B.J K M J N J J J J J M U O N M N K K +.F$G$H$*$*$*$*$*$&$&$&$&$&$*$%$*$%$&$%$*$%$I$J$K$ ", -" L$M$N$A@g.N.g.g.g.g.g.E+g.g.M.y.h+g.h+N.,+O$P$Q$w K K K N N N N K J K K U K N K N K J d+R$S$T$%$%$%$*$%$o$3$o$%$%$*$%$%$%$%$%$%$U$V$W$ ", -" /+:.X$[.M.g.g.g.g.g.S+g.g.,+g.M.g.,+M.g.S+2#Y$t.K U K J J J J U J U O U U J U J O J Z$`$ %%$&$&$&$&$&$*$&$=$=$&$&$%$&$%$=$&$' .%+%@% ", -" #%$%k x.1+g.g.g.g.g.E+g.g.M.S+g.g.M.g.g.g.f.&.F.B.K K N K K K K J K K K O K K K K -.%%&%e$&$%$%$%$%$%$*$%$=$=$&$%$%$%$%$%$%$*%=%-% ", -" ! ;%>%f.M.g.g.g.g.g.g.g.M.y.h+g.M.g.g.y.x.%#,%c.K K J O O K U J U K U O K K O J q '%)%^$3$%$%$%$3$%$*$4$=$5$4$3$%$%$%$%$!%~%{% ", -" 7$]%P#M.M.g.g.g.,+y.y.M.h+M.y.M.,+y.M.^%/%(%y K M J N J J U J U M U K N M N K _%j 6$%$3$4$4$4$&$4$*$4$=$5$4$&$%$4$&$:%|#<%[% ", -" }%|%k 1%g.g.g.g.E+N.,+,+g.,+,+,+,+,+,+[.2%3%V K K J O O K K J K M U O K M O B.C+4%5%&$3$%$%$%$*$%$o$4$o$%$5$*$%$&$2$. k 6% ", -" 7%8%9%x.g.g.g.E+y.S+M.S+M.S+M.E+S+S+g.f.F+0%J M J N J T T J T M O J M T N ;.a%b%c%&$*$&$&$&$&$&$&$&$&$&$&$&$&$%$n$d%e% ", -" f%g%h%g+g.g.E+g.g.M.S+M.g.M.,+g.M.M.A@`@G+;.M J N J J J J J M U O N M N v i%j%k%*$*$*$*$*$*$*$&$&$&$&$&$*$%$l%m%n%o% ", -" p%k |+M.g.E+g.g.M.y.h+g.h+N.g.M.M.^%q%r%v K N N N N K J K K U K N K K _.#+3$&$*$3$%$%$%$*$%$o$3$o$%$%$%$s%t%k u% ", -" v%w%x%x.g.S+g.g.,+g.M.g.,+M.g.M.M.g+y%z%'.J J J J J U J U O U U J U B.A%B%C%%$&$*$&$&$&$&$&$*$&$=$=$&$&$D%E%F% ", -" G%H%I%f.g.g.g.M.S+g.g.M.g.g.E+E+M.f.J%V K N K K K K J K K K O K K y K%>@L%%$%$%$%$%$%$%$%$*$%$=$=$%$M%N%O% ", -" P%Q%R%[.M.g.M.y.h+g.M.g.g.y.y.g.A@S%T%-.J O O K U J U K U O K K q ]#U%l%%$3$3$%$%$%$3$%$*$4$=$&$^$|#V%r$ ", -" A$W%k 2+g.M.M.h+M.y.M.,+y.M.M.g.f.X%Y%r J N J J U J U M U K N K |@Z%`% &4$&$3$4$4$4$&$4$*$4$=$y$.&k +& ", -" W.@&#&2+g.,+g.,+,+,+,+,+,+,+,+g+..Q.+.J O O K K J K M U O K J $&%&&&%$%$*$3$%$%$%$*$%$o$&$*&=&-&;& ", -" >&,&'&M.M.S+M.S+M.E+S+S+S+,+M.)&!&q K N J T T J T M O J M I ~&{&C%&$4$&$*$&$&$&$&$&$&$%$M%]&^&/& ", -" (&k _&1+M.M.g.M.,+g.M.M.g.g.x.k :&N N J J J J J M U O N V <&[&k%%$*$*$*$*$*$*$*$*$&$6$}&F+|& ", -" B$1&2&h.g.h+g.h+N.g.M.M.g.g.f.3&4&w J N N K J K K U K K 5&6&7&:%%$%$*$3$%$%$%$*$&$S$*%8&9& ", -" D 0&h%a&g.g.,+M.g.M.M.g.g.[.b&c&_.T J J U J U O U U O d&e&n$5$%$&$&$*$&$&$&$&$&$U$f&g& ", -" h&k S+g.M.M.g.g.E+E+g.E+M.l@i&V ].K K K J K K K O c.j&k&l&%$%$%$%$%$%$%$%$%$m&n&o&p& ", -" q&r&s&A@M.M.g.g.y.y.N.g.M.>+@@J t&O K U J U K U J V )&u&V#3$%$%$3$3$%$%$&$%$. k v& ", -" w&x&y&^%g.,+y.M.M.g.g.,+A@z&A&u.J J U J U M U K I.B&C& &4$%$4$&$3$4$4$%$$$D&E& ", -" F&G&6#[.g.,+,+,+,+,+N.[.H&I&v J K K J K M U u.I h 4@&$3$%$%$*$3$%$%$J&K&L&r$ ", -" M&N&k 2+g.S+S+S+,+E+M.M.O&W@n@K T T J T M O P&Q&R&!%%$&$&$4$&$*$%$S&T&k U& ", -" < V&W&C@g.M.M.g.g.M.M.O.X&K Y&J J J J M J I Z&`&V#%$*$%$*$*$*$%$$$ *.* ", -" D +*@*O.M.M.g.g.h+g.>+9@#*t&N K J K K K I.$*%*&$%$3$%$%$&$%$&&&***=* ", -" t@k 1%1+g.g.g.N.g.g+-*;*5.K U J U O ].I >*,*&$%$&$%$&$&$'*)*!*~* ", -" e@{*0$A@g.g.E+M.g.1+T+]*I.T K J K K E.^*/*=&%$%$%$%$%$H$(*k _* ", -" :*0&<*[.M.g.h+N.g.h+i@!+K U J U K -.[*}*'*%$%$3$%$%$|*1*K& ", -" 2*k 3*g.g.h+g.g.2+4*F ].U J U J Y.5*6*6$3$%$4$&$7*8*9*u% ", -" 0*a*b*2+g.N.N.S+f.c*d*J K J K K V e*f**&%$o$%$%$g*k h* ", -" i*j*k*f.g.N.g.g.l*r+'.K J T ].m*n* %%$*$=$%$c%o*p* ", -" < q*_#[.g.g.1+3#,.2.J J J J r*s*C%&$*$%$t*u*v*w* ", -" x*k C@g.g.g.A@J%u$J J K '.y*z**&%$%$:%O#A*B* ", -" C*V&D*#@g.M.>+&#E*J J J 2.z&& H$&$&$(*k F* ", -" x+G*'&g+M.O$H*I*w J J J*K**%%$%$c%L*M* ", -" N*k f.y.E+D+Y$t.O B.+@O*$$&$k%8*P*x+ ", -" Q*R*S*D$g.O.S%:&J w T*U*k%V*W*k X* ", -" < Y**@[.x.Z*m#A.G@`* =2$=&.=+= ", -" @=k [$f.#=k.w $=%=~ U$&=*=== ", -" -=;=s&2+O&>=_.E$,=$$$+'=)= ", -" !=j*~=C@k {=]=^=I$k /= ", -" 3@q*S+Z@F (=S&_=:=<= ", -" [=}=|=1=2=3=4=5= ", -" 6=7=9 $#8=e&9= ", -" Z+0=k k a= ", -" t%k b=^+ ", -" c=d=d$ ", -" e= "}; diff --git a/share/pixmaps/check.ico b/share/pixmaps/check.ico deleted file mode 100644 index 0c4e6e81..00000000 Binary files a/share/pixmaps/check.ico and /dev/null differ diff --git a/share/pixmaps/favicon.ico b/share/pixmaps/favicon.ico deleted file mode 100644 index b7a55e05..00000000 Binary files a/share/pixmaps/favicon.ico and /dev/null differ diff --git a/share/pixmaps/nsis-header.bmp b/share/pixmaps/nsis-header.bmp index 5eb10ae7..9ab0ce25 100644 Binary files a/share/pixmaps/nsis-header.bmp and b/share/pixmaps/nsis-header.bmp differ diff --git a/share/pixmaps/nsis-wizard.bmp b/share/pixmaps/nsis-wizard.bmp index 330de6bc..71255c68 100644 Binary files a/share/pixmaps/nsis-wizard.bmp and b/share/pixmaps/nsis-wizard.bmp differ diff --git a/share/pixmaps/send16.bmp b/share/pixmaps/send16.bmp deleted file mode 100644 index 676b5c4b..00000000 Binary files a/share/pixmaps/send16.bmp and /dev/null differ diff --git a/share/pixmaps/send16mask.bmp b/share/pixmaps/send16mask.bmp deleted file mode 100644 index 06c747f9..00000000 Binary files a/share/pixmaps/send16mask.bmp and /dev/null differ diff --git a/share/pixmaps/send16masknoshadow.bmp b/share/pixmaps/send16masknoshadow.bmp deleted file mode 100644 index faf24e0d..00000000 Binary files a/share/pixmaps/send16masknoshadow.bmp and /dev/null differ diff --git a/share/pixmaps/send20.bmp b/share/pixmaps/send20.bmp deleted file mode 100644 index 2b90422b..00000000 Binary files a/share/pixmaps/send20.bmp and /dev/null differ diff --git a/share/pixmaps/send20mask.bmp b/share/pixmaps/send20mask.bmp deleted file mode 100644 index f124d0da..00000000 Binary files a/share/pixmaps/send20mask.bmp and /dev/null differ diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in new file mode 100644 index 00000000..6a34d64c --- /dev/null +++ b/share/qt/Info.plist.in @@ -0,0 +1,106 @@ + + + + + LSMinimumSystemVersion + 10.7.0 + + LSArchitecturePriority + + x86_64 + + + CFBundleIconFile + bitcoin.icns + + CFBundlePackageType + APPL + + CFBundleGetInfoString + @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@, Copyright © 2009-@COPYRIGHT_YEAR@ @COPYRIGHT_HOLDERS_FINAL@ + + CFBundleShortVersionString + @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@ + + CFBundleVersion + @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@ + + CFBundleSignature + ???? + + CFBundleExecutable + Bitcoin-Qt + + CFBundleName + Bitcoin-Qt + + LSHasLocalizedDisplayName + + + CFBundleIdentifier + org.bitcoinfoundation.Bitcoin-Qt + + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + org.bitcoin.BitcoinPayment + CFBundleURLSchemes + + bitcoin + + + + + UTExportedTypeDeclarations + + + UTTypeIdentifier + org.bitcoin.paymentrequest + UTTypeDescription + Bitcoin payment request + UTTypeConformsTo + + public.data + + UTTypeTagSpecification + + public.mime-type + application/x-bitcoin-payment-request + public.filename-extension + + bitcoinpaymentrequest + + + + + + CFBundleDocumentTypes + + + CFBundleTypeRole + Editor + LSItemContentTypes + + org.bitcoin.paymentrequest + + LSHandlerRank + Owner + + + + NSPrincipalClass + NSApplication + + NSHighResolutionCapable + True + + LSAppNapIsDisabled + True + + LSApplicationCategoryType + public.app-category.finance + + diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py index 771f28ab..2a6e4b93 100644 --- a/share/qt/extract_strings_qt.py +++ b/share/qt/extract_strings_qt.py @@ -5,8 +5,11 @@ ''' from subprocess import Popen, PIPE import glob +import operator +import os +import sys -OUT_CPP="src/qt/bitcoinstrings.cpp" +OUT_CPP="qt/bitcoinstrings.cpp" EMPTY=['""'] def parse_po(text): @@ -45,16 +48,20 @@ def parse_po(text): return messages -files = glob.glob('src/*.cpp') + glob.glob('src/*.h') +files = sys.argv[1:] # xgettext -n --keyword=_ $FILES -child = Popen(['xgettext','--output=-','-n','--keyword=_'] + files, stdout=PIPE) +XGETTEXT=os.getenv('XGETTEXT', 'xgettext') +child = Popen([XGETTEXT,'--output=-','-n','--keyword=_'] + files, stdout=PIPE) (out, err) = child.communicate() messages = parse_po(out) f = open(OUT_CPP, 'w') -f.write("""#include +f.write(""" + +#include + // Automatically generated by extract_strings.py #ifdef __GNUC__ #define UNUSED __attribute__((unused)) @@ -62,9 +69,14 @@ def parse_po(text): #define UNUSED #endif """) -f.write('static const char UNUSED *bitcoin_strings[] = {') +f.write('static const char UNUSED *bitcoin_strings[] = {\n') +f.write('QT_TRANSLATE_NOOP("bitcoin-core", "%s"),\n' % (os.getenv('PACKAGE_NAME'),)) +f.write('QT_TRANSLATE_NOOP("bitcoin-core", "%s"),\n' % (os.getenv('COPYRIGHT_HOLDERS'),)) +if os.getenv('COPYRIGHT_HOLDERS_SUBSTITUTION') != os.getenv('PACKAGE_NAME'): + f.write('QT_TRANSLATE_NOOP("bitcoin-core", "%s"),\n' % (os.getenv('COPYRIGHT_HOLDERS_SUBSTITUTION'),)) +messages.sort(key=operator.itemgetter(0)) for (msgid, msgstr) in messages: if msgid != EMPTY: f.write('QT_TRANSLATE_NOOP("bitcoin-core", %s),\n' % ('\n'.join(msgid))) -f.write('};') +f.write('};\n') f.close() diff --git a/share/qt/img/reload.xcf b/share/qt/img/reload.xcf deleted file mode 100644 index dc8be628..00000000 Binary files a/share/qt/img/reload.xcf and /dev/null differ diff --git a/share/qt/make_spinner.py b/share/qt/make_spinner.py deleted file mode 100644 index 136aff3c..00000000 --- a/share/qt/make_spinner.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python -# W.J. van der Laan, 2011 -# Make spinning .mng animation from a .png -# Requires imagemagick 6.7+ -from __future__ import division -from os import path -from PIL import Image -from subprocess import Popen - -SRC='img/reload_scaled.png' -DST='../../src/qt/res/movies/update_spinner.mng' -TMPDIR='/tmp' -TMPNAME='tmp-%03i.png' -NUMFRAMES=35 -FRAMERATE=10.0 -CONVERT='convert' -CLOCKWISE=True -DSIZE=(16,16) - -im_src = Image.open(SRC) - -if CLOCKWISE: - im_src = im_src.transpose(Image.FLIP_LEFT_RIGHT) - -def frame_to_filename(frame): - return path.join(TMPDIR, TMPNAME % frame) - -frame_files = [] -for frame in xrange(NUMFRAMES): - rotation = (frame + 0.5) / NUMFRAMES * 360.0 - if CLOCKWISE: - rotation = -rotation - im_new = im_src.rotate(rotation, Image.BICUBIC) - im_new.thumbnail(DSIZE, Image.ANTIALIAS) - outfile = frame_to_filename(frame) - im_new.save(outfile, 'png') - frame_files.append(outfile) - -p = Popen([CONVERT, "-delay", str(FRAMERATE), "-dispose", "2"] + frame_files + [DST]) -p.communicate() - - - diff --git a/share/qt/make_windows_icon.sh b/share/qt/make_windows_icon.sh deleted file mode 100644 index f775a305..00000000 --- a/share/qt/make_windows_icon.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# create multiresolution windows icon -ICON_DST=../../src/qt/res/icons/novacoin.ico - -convert ../../src/qt/res/icons/novacoin-16.png ../../src/qt/res/icons/novacoin-32.png ../../src/qt/res/icons/novacoin-48.png ${ICON_DST} diff --git a/share/qt/protobuf.pri b/share/qt/protobuf.pri new file mode 100644 index 00000000..865fe865 --- /dev/null +++ b/share/qt/protobuf.pri @@ -0,0 +1,35 @@ +# Based on: http://code.google.com/p/ostinato/source/browse/protobuf.pri +# +# Qt qmake integration with Google Protocol Buffers compiler protoc +# +# To compile protocol buffers with qt qmake, specify PROTOS variable and +# include this file +# +# Example: +# PROTOS = a.proto b.proto +# include(protobuf.pri) +# +# Set PROTO_PATH if you need to set the protoc --proto_path search path +# Set PROTOC to the path to the protoc compiler if it is not in your $PATH +# + +isEmpty(PROTO_DIR):PROTO_DIR = . +isEmpty(PROTOC):PROTOC = protoc + +PROTOPATHS = +for(p, PROTO_PATH):PROTOPATHS += --proto_path=$${p} + +protobuf_decl.name = protobuf header +protobuf_decl.input = PROTOS +protobuf_decl.output = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.h +protobuf_decl.commands = $${PROTOC} --cpp_out="$${PROTO_DIR}" $${PROTOPATHS} --proto_path=${QMAKE_FILE_IN_PATH} ${QMAKE_FILE_NAME} +protobuf_decl.variable_out = GENERATED_FILES +QMAKE_EXTRA_COMPILERS += protobuf_decl + +protobuf_impl.name = protobuf implementation +protobuf_impl.input = PROTOS +protobuf_impl.output = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.cc +protobuf_impl.depends = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.h +protobuf_impl.commands = $$escape_expand(\\n) +protobuf_impl.variable_out = GENERATED_SOURCES +QMAKE_EXTRA_COMPILERS += protobuf_impl diff --git a/share/rpcuser/README.md b/share/rpcuser/README.md new file mode 100644 index 00000000..12a8e6fb --- /dev/null +++ b/share/rpcuser/README.md @@ -0,0 +1,10 @@ +RPC Tools +--------------------- + +### [RPCUser](/share/rpcuser) ### + +Create an RPC user login credential. + +Usage: + + ./rpcuser.py diff --git a/share/rpcuser/rpcuser.py b/share/rpcuser/rpcuser.py new file mode 100644 index 00000000..38654488 --- /dev/null +++ b/share/rpcuser/rpcuser.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Bitcoin Core developers +# Copyright (c) 2015-2017 The Bitcoin Unlimited developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import hashlib +import sys +import os +from random import SystemRandom +import base64 +import hmac + +if len(sys.argv) < 2: + sys.stderr.write('Please include username as an argument.\n') + sys.exit(0) + +username = sys.argv[1] + +#This uses os.urandom() underneath +cryptogen = SystemRandom() + +#Create 16 byte hex salt +salt_sequence = [cryptogen.randrange(256) for i in range(16)] +hexseq = list(map(hex, salt_sequence)) +salt = "".join([x[2:] for x in hexseq]) + +#Create 32 byte b64 password +password = base64.urlsafe_b64encode(os.urandom(32)) + +digestmod = hashlib.sha256 + +if sys.version_info.major >= 3: + password = password.decode('utf-8') + digestmod = 'SHA256' + +m = hmac.new(bytearray(salt, 'utf-8'), bytearray(password, 'utf-8'), digestmod) +result = m.hexdigest() + +print("String to be appended to bitcoin.conf:") +print("rpcauth="+username+":"+salt+"$"+result) +print("Your password:\n"+password) diff --git a/share/setup.nsi b/share/setup.nsi.in similarity index 62% rename from share/setup.nsi rename to share/setup.nsi.in index 2cc647fe..c062f96a 100644 --- a/share/setup.nsi +++ b/share/setup.nsi.in @@ -1,33 +1,36 @@ -Name BottleCaps +Name "@PACKAGE_NAME@ (@WINDOWS_BITS@-bit)" RequestExecutionLevel highest SetCompressor /SOLID lzma # General Symbol Definitions !define REGKEY "SOFTWARE\$(^Name)" -!define VERSION 0.3.0 -!define COMPANY "BottleCaps project" -!define URL http:// +!define VERSION @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@ +!define COMPANY "@PACKAGE_NAME@ project" +!define URL @PACKAGE_URL@ # MUI Symbol Definitions -!define MUI_ICON "../share/pixmaps/BottleCaps.ico" -!define MUI_WELCOMEFINISHPAGE_BITMAP "../share/pixmaps/nsis-wizard.bmp" +!define MUI_ICON "@abs_top_srcdir@/share/pixmaps/bitcoin.ico" +!define MUI_WELCOMEFINISHPAGE_BITMAP "@abs_top_srcdir@/share/pixmaps/nsis-wizard.bmp" !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_RIGHT -!define MUI_HEADERIMAGE_BITMAP "../share/pixmaps/nsis-header.bmp" +!define MUI_HEADERIMAGE_BITMAP "@abs_top_srcdir@/share/pixmaps/nsis-header.bmp" !define MUI_FINISHPAGE_NOAUTOCLOSE !define MUI_STARTMENUPAGE_REGISTRY_ROOT HKLM !define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY} !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME StartMenuGroup -!define MUI_STARTMENUPAGE_DEFAULTFOLDER BottleCaps -!define MUI_FINISHPAGE_RUN $INSTDIR\BottleCaps-qt.exe +!define MUI_STARTMENUPAGE_DEFAULTFOLDER "@PACKAGE_NAME@" +!define MUI_FINISHPAGE_RUN $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" -!define MUI_UNWELCOMEFINISHPAGE_BITMAP "../share/pixmaps/nsis-wizard.bmp" +!define MUI_UNWELCOMEFINISHPAGE_BITMAP "@abs_top_srcdir@/share/pixmaps/nsis-wizard.bmp" !define MUI_UNFINISHPAGE_NOAUTOCLOSE # Included files !include Sections.nsh !include MUI2.nsh +!if "@WINDOWS_BITS@" == "64" +!include x64.nsh +!endif # Variables Var StartMenuGroup @@ -45,14 +48,18 @@ Var StartMenuGroup !insertmacro MUI_LANGUAGE English # Installer attributes -OutFile BottleCaps-0.3.0-win32-setup.exe -InstallDir $PROGRAMFILES\BottleCaps +OutFile @abs_top_srcdir@/@PACKAGE_TARNAME@-${VERSION}-win@WINDOWS_BITS@-setup.exe +!if "@WINDOWS_BITS@" == "64" +InstallDir $PROGRAMFILES64\Bitcoin +!else +InstallDir $PROGRAMFILES\Bitcoin +!endif CRCCheck on XPStyle on BrandingText " " ShowInstDetails show -VIProductVersion 0.3.0.0 -VIAddVersionKey ProductName BottleCaps +VIProductVersion ${VERSION}.@CLIENT_VERSION_BUILD@ +VIAddVersionKey ProductName "@PACKAGE_NAME@" VIAddVersionKey ProductVersion "${VERSION}" VIAddVersionKey CompanyName "${COMPANY}" VIAddVersionKey CompanyWebsite "${URL}" @@ -66,19 +73,16 @@ ShowUninstDetails show Section -Main SEC0000 SetOutPath $INSTDIR SetOverwrite on - File ../release/BottleCaps-qt.exe - File /oname=license.txt ../COPYING - File /oname=readme.txt ../doc/README_windows.txt + File @abs_top_srcdir@/release/@BITCOIN_GUI_NAME@@EXEEXT@ + File /oname=COPYING.txt @abs_top_srcdir@/COPYING + File /oname=readme.txt @abs_top_srcdir@/doc/README_windows.txt SetOutPath $INSTDIR\daemon - File ../src/BottleCapsd.exe - SetOutPath $INSTDIR\src - File /r /x *.exe /x *.o ../src\*.* + File @abs_top_srcdir@/release/@BITCOIN_DAEMON_NAME@@EXEEXT@ + File @abs_top_srcdir@/release/@BITCOIN_CLI_NAME@@EXEEXT@ + SetOutPath $INSTDIR\doc + File /r @abs_top_srcdir@/doc\*.* SetOutPath $INSTDIR WriteRegStr HKCU "${REGKEY}\Components" Main 1 - - # Remove old wxwidgets-based-BottleCaps executable and locales: - Delete /REBOOTOK $INSTDIR\BottleCaps.exe - RMDir /r /REBOOTOK $INSTDIR\locale SectionEnd Section -post SEC0001 @@ -87,8 +91,8 @@ Section -post SEC0001 WriteUninstaller $INSTDIR\uninstall.exe !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory $SMPROGRAMS\$StartMenuGroup - CreateShortcut "$SMPROGRAMS\$StartMenuGroup\BottleCaps.lnk" $INSTDIR\BottleCaps-qt.exe - CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall BottleCaps.lnk" $INSTDIR\uninstall.exe + CreateShortcut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ + CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" $INSTDIR\uninstall.exe !insertmacro MUI_STARTMENU_WRITE_END WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)" WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayVersion "${VERSION}" @@ -98,12 +102,10 @@ Section -post SEC0001 WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" UninstallString $INSTDIR\uninstall.exe WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1 WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1 - - # BottleCaps: URI handling disabled for 0.6.0 - WriteRegStr HKCR "BottleCaps" "URL Protocol" "" - WriteRegStr HKCR "BottleCaps" "" "URL:BottleCaps" - WriteRegStr HKCR "BottleCaps\DefaultIcon" "" $INSTDIR\BottleCaps-qt.exe - WriteRegStr HKCR "BottleCaps\shell\open\command" "" '"$INSTDIR\BottleCaps-qt.exe" "$$1"' + WriteRegStr HKCR "@PACKAGE_TARNAME@" "URL Protocol" "" + WriteRegStr HKCR "@PACKAGE_TARNAME@" "" "URL:Bitcoin" + WriteRegStr HKCR "@PACKAGE_TARNAME@\DefaultIcon" "" $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ + WriteRegStr HKCR "@PACKAGE_TARNAME@\shell\open\command" "" '"$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "%1"' SectionEnd # Macro for selecting uninstaller sections @@ -121,19 +123,19 @@ done${UNSECTION_ID}: # Uninstaller sections Section /o -un.Main UNSEC0000 - Delete /REBOOTOK $INSTDIR\BottleCaps-qt.exe - Delete /REBOOTOK $INSTDIR\license.txt + Delete /REBOOTOK $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ + Delete /REBOOTOK $INSTDIR\COPYING.txt Delete /REBOOTOK $INSTDIR\readme.txt RMDir /r /REBOOTOK $INSTDIR\daemon - RMDir /r /REBOOTOK $INSTDIR\src + RMDir /r /REBOOTOK $INSTDIR\doc DeleteRegValue HKCU "${REGKEY}\Components" Main SectionEnd Section -un.post UNSEC0001 DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" - Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Uninstall BottleCaps.lnk" - Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\BottleCaps.lnk" - Delete /REBOOTOK "$SMSTARTUP\BottleCaps.lnk" + Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" + Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" + Delete /REBOOTOK "$SMSTARTUP\Bitcoin.lnk" Delete /REBOOTOK $INSTDIR\uninstall.exe Delete /REBOOTOK $INSTDIR\debug.log Delete /REBOOTOK $INSTDIR\db.log @@ -141,7 +143,7 @@ Section -un.post UNSEC0001 DeleteRegValue HKCU "${REGKEY}" Path DeleteRegKey /IfEmpty HKCU "${REGKEY}\Components" DeleteRegKey /IfEmpty HKCU "${REGKEY}" - DeleteRegKey HKCR "BottleCaps" + DeleteRegKey HKCR "@PACKAGE_TARNAME@" RmDir /REBOOTOK $SMPROGRAMS\$StartMenuGroup RmDir /REBOOTOK $INSTDIR Push $R0 @@ -154,6 +156,15 @@ SectionEnd # Installer functions Function .onInit InitPluginsDir +!if "@WINDOWS_BITS@" == "64" + ${If} ${RunningX64} + ; disable registry redirection (enable access to 64-bit portion of registry) + SetRegView 64 + ${Else} + MessageBox MB_OK|MB_ICONSTOP "Cannot install 64-bit version on a 32-bit system." + Abort + ${EndIf} +!endif FunctionEnd # Uninstaller functions diff --git a/share/ui.rc b/share/ui.rc deleted file mode 100644 index 431d8fd2..00000000 --- a/share/ui.rc +++ /dev/null @@ -1,15 +0,0 @@ -BottleCaps ICON "pixmaps/BottleCaps.ico" - -#include "wx/msw/wx.rc" - -check ICON "pixmaps/check.ico" -send16 BITMAP "pixmaps/send16.bmp" -send16mask BITMAP "pixmaps/send16mask.bmp" -send16masknoshadow BITMAP "pixmaps/send16masknoshadow.bmp" -send20 BITMAP "pixmaps/send20.bmp" -send20mask BITMAP "pixmaps/send20mask.bmp" -addressbook16 BITMAP "pixmaps/addressbook16.bmp" -addressbook16mask BITMAP "pixmaps/addressbook16mask.bmp" -addressbook20 BITMAP "pixmaps/addressbook20.bmp" -addressbook20mask BITMAP "pixmaps/addressbook20mask.bmp" -favicon ICON "pixmaps/favicon.ico" diff --git a/src/.clang-format b/src/.clang-format new file mode 100644 index 00000000..dc22b673 --- /dev/null +++ b/src/.clang-format @@ -0,0 +1,53 @@ +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AlignEscapedNewlinesLeft: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackParameters: false +BreakBeforeBinaryOperators: false +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, BOOST_REVERSE_FOREACH ] +IndentCaseLabels: false +IndentFunctionDeclarationAfterType: false +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Right +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +Standard: Cpp03 +TabWidth: 8 +UseTab: Never +AlignTrailingComments: false diff --git a/src/.formatted-files b/src/.formatted-files new file mode 100644 index 00000000..244a3b79 --- /dev/null +++ b/src/.formatted-files @@ -0,0 +1,314 @@ +addrman.cpp +addrman.h +allowed_args.cpp +allowed_args.h +amount.cpp +amount.h +arith_uint256.cpp +arith_uint256.h +bandb.cpp +bandb.h +banentry.cpp +banentry.h +base58.cpp +base58.h +bitcoin-cli.cpp +bitcoind.cpp +bitcoin-tx.cpp +bitnodes.cpp +bitnodes.h +bloom.cpp +bloom.h +buip055fork.cpp +buip055fork.h +chain.cpp +chain.h +chainparamsbase.cpp +chainparamsbase.h +chainparams.cpp +chainparams.h +chainparamsseeds.h +checkpoints.cpp +checkpoints.h +checkqueue.h +clientversion.cpp +clientversion.h +coincontrol.h +coins.cpp +coins.h +compat.h +compressor.cpp +compressor.h +connmgr.cpp +connmgr.h +core_io.h +core_memusage.h +core_read.cpp +core_write.cpp +dbwrapper.cpp +dbwrapper.h +dosman.cpp +dosman.h +ecwrapper.cpp +expedited.cpp +expedited.h +globals.cpp +hash.cpp +hash.h +httprpc.cpp +httprpc.h +httpserver.cpp +httpserver.h +init.cpp +init.h +key.cpp +key.h +keystore.cpp +keystore.h +leakybucket.h +limitedmap.h +main.cpp +main.h +memusage.h +merkleblock.cpp +merkleblock.h +miner.cpp +miner.h +netaddress.cpp +netaddress.h +netbase.cpp +netbase.h +net.cpp +net.h +nodestate.cpp +nodestate.h +noui.cpp +noui.h +parallel.cpp +parallel.h +pow.cpp +pow.h +prevector.h +protocol.cpp +protocol.h +pubkey.cpp +pubkey.h +random.cpp +random.h +requestManager.cpp +requestManager.h +rest.cpp +reverselock.h +scheduler.cpp +scheduler.h +serialize.h +stat.h +streams.h +sync.cpp +sync.h +thinblock.cpp +thinblock.h +threadsafety.h +timedata.cpp +timedata.h +tinyformat.h +torcontrol.cpp +torcontrol.h +tweak.cpp +tweak.h +txdb.cpp +txdb.h +txmempool.cpp +txmempool.h +ui_interface.h +uint256.cpp +uint256.h +undo.h +unlimited.cpp +unlimited.h +util.cpp +util.h +utilmoneystr.cpp +utilmoneystr.h +utilstrencodings.cpp +utilstrencodings.h +utiltime.cpp +utiltime.h +validationinterface.cpp +validationinterface.h +versionbits.cpp +versionbits.h +version.h +qt/addressbookpage.cpp +qt/addressbookpage.h +qt/addresstablemodel.cpp +qt/addresstablemodel.h +qt/askpassphrasedialog.cpp +qt/askpassphrasedialog.h +qt/bantablemodel.cpp +qt/bantablemodel.h +qt/bitcoinaddressvalidator.cpp +qt/bitcoinaddressvalidator.h +qt/bitcoinamountfield.cpp +qt/bitcoinamountfield.h +qt/bitcoin.cpp +qt/bitcoingui.cpp +qt/bitcoingui.h +qt/bitcoinstrings.cpp +qt/bitcoinunits.cpp +qt/bitcoinunits.h +qt/clientmodel.cpp +qt/clientmodel.h +qt/coincontroldialog.cpp +qt/coincontroldialog.h +qt/coincontroltreewidget.cpp +qt/coincontroltreewidget.h +qt/csvmodelwriter.cpp +qt/csvmodelwriter.h +qt/editaddressdialog.cpp +qt/editaddressdialog.h +qt/guiconstants.h +qt/guiutil.cpp +qt/guiutil.h +qt/intro.cpp +qt/intro.h +qt/macdockiconhandler.h +qt/macnotificationhandler.h +qt/networkstyle.cpp +qt/networkstyle.h +qt/notificator.cpp +qt/notificator.h +qt/openuridialog.cpp +qt/openuridialog.h +qt/optionsdialog.cpp +qt/optionsdialog.h +qt/optionsmodel.cpp +qt/optionsmodel.h +qt/overviewpage.cpp +qt/overviewpage.h +qt/paymentrequestplus.cpp +qt/paymentrequestplus.h +qt/paymentserver.cpp +qt/paymentserver.h +qt/peertablemodel.cpp +qt/peertablemodel.h +qt/platformstyle.cpp +qt/platformstyle.h +qt/qvalidatedlineedit.cpp +qt/qvalidatedlineedit.h +qt/qvaluecombobox.cpp +qt/qvaluecombobox.h +qt/receivecoinsdialog.cpp +qt/receivecoinsdialog.h +qt/receivefreezedialog.cpp +qt/receivefreezedialog.h +qt/receiverequestdialog.cpp +qt/receiverequestdialog.h +qt/recentrequeststablemodel.cpp +qt/recentrequeststablemodel.h +qt/rpcconsole.cpp +qt/rpcconsole.h +qt/sendcoinsdialog.cpp +qt/sendcoinsdialog.h +qt/sendcoinsentry.cpp +qt/sendcoinsentry.h +qt/signverifymessagedialog.cpp +qt/signverifymessagedialog.h +qt/splashscreen.cpp +qt/splashscreen.h +qt/trafficgraphwidget.cpp +qt/trafficgraphwidget.h +qt/transactiondesc.cpp +qt/transactiondescdialog.cpp +qt/transactiondescdialog.h +qt/transactiondesc.h +qt/transactionfilterproxy.cpp +qt/transactionfilterproxy.h +qt/transactionrecord.cpp +qt/transactionrecord.h +qt/transactiontablemodel.cpp +qt/transactiontablemodel.h +qt/transactionview.cpp +qt/transactionview.h +qt/unlimiteddialog.cpp +qt/unlimiteddialog.h +qt/unlimitedmodel.cpp +qt/unlimitedmodel.h +qt/utilitydialog.cpp +qt/utilitydialog.h +qt/walletframe.cpp +qt/walletframe.h +qt/walletmodel.cpp +qt/walletmodel.h +qt/walletmodeltransaction.cpp +qt/walletmodeltransaction.h +qt/walletview.cpp +qt/walletview.h +qt/winshutdownmonitor.cpp +qt/winshutdownmonitor.h +test/addrman_tests.cpp +test/alert_tests.cpp +test/allocator_tests.cpp +test/arith_uint256_tests.cpp +test/bandb_tests.cpp +test/base32_tests.cpp +test/base58_tests.cpp +test/base64_tests.cpp +test/bip32_tests.cpp +test/bloom_tests.cpp +test/bswap_tests.cpp +test/buip055_test.cpp +test/checkblock_tests.cpp +test/Checkpoints_tests.cpp +test/coins_tests.cpp +test/compress_tests.cpp +test/crypto_tests.cpp +test/dbwrapper_tests.cpp +test/DoS_tests.cpp +test/excessiveblock_test.cpp +test/exploit_tests.cpp +test/fork_tests.cpp +test/getarg_tests.cpp +test/hash_tests.cpp +test/key_tests.cpp +test/limitedmap_tests.cpp +test/main_tests.cpp +test/mempool_tests.cpp +test/merkle_tests.cpp +test/miner_tests.cpp +test/multisig_tests.cpp +test/netbase_tests.cpp +test/net_tests.cpp +test/pmt_tests.cpp +test/policyestimator_tests.cpp +test/pow_tests.cpp +test/prevector_tests.cpp +test/reverselock_tests.cpp +test/rpc_tests.cpp +test/sanity_tests.cpp +test/scheduler_tests.cpp +test/scriptnum10.h +test/scriptnum_tests.cpp +test/script_P2SH_tests.cpp +test/script_tests.cpp +test/serialize_tests.cpp +test/sighash_tests.cpp +test/sigopcount_tests.cpp +test/skiplist_tests.cpp +test/stat_tests.cpp +test/streams_tests.cpp +test/test_bitcoin.cpp +test/test_bitcoin_fuzzy.cpp +test/test_bitcoin.h +test/testutil.cpp +test/testutil.h +test/thinblock_data_tests.cpp +test/thinblock_tests.cpp +test/thinblock_util_tests.cpp +test/timedata_tests.cpp +test/transaction_tests.cpp +test/txvalidationcache_tests.cpp +test/uint256_tests.cpp +test/univalue_tests.cpp +test/util_tests.cpp +test/versionbits_tests.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..d56d7334 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,261 @@ +# The name of our project is "ECCOIN". CMakeLists files in this project can +# refer to the root source directory of the project as ${ECCOIN_SOURCE_DIR} and +# to the root binary directory of the project as ${ECCOIN_BINARY_DIR}. +cmake_minimum_required(VERSION 2.8.11) +project (ECCOIN) + +# CMake Modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") + +# Setup Sources +set(DIR_SOURCES + txdb.cpp + key.cpp + addrman.cpp + amount.cpp + arith_uint256.cpp + base58.cpp + chain/blockindex.cpp + bloom.cpp + chain/chain.cpp + chain/chainman.cpp + networks/netman.cpp + chain/checkpoints.cpp + clientversion.cpp + coins.cpp + compressor.cpp + core_read.cpp + core_write.cpp + dbwrapper.cpp + crypto/hash.cpp + keystore.cpp + main.cpp + merkleblock.cpp + messages.cpp + miner.cpp + net.cpp + netbase.cpp + noui.cpp + pow.cpp + processblock.cpp + processheader.cpp + protocol.cpp + pubkey.cpp + random.cpp + scheduler.cpp + sync.cpp + timedata.cpp + torcontrol.cpp + txmempool.cpp + uint256.cpp + util/util.cpp + fs.cpp + args.cpp + util/utilmoneystr.cpp + util/utilstrencodings.cpp + util/utiltime.cpp + validationinterface.cpp + versionbits.cpp + wallet/crypter.cpp + wallet/db.cpp + wallet/wallet.cpp + wallet/wallet_ismine.cpp + wallet/walletdb.cpp + support/cleanse.cpp + support/pagelocker.cpp + script/bitcoinconsensus.cpp + script/interpreter.cpp + script/script.cpp + script/script_error.cpp + script/sigcache.cpp + script/sign.cpp + script/standard.cpp + chain/block.cpp + tx/tx.cpp + policy/fees.cpp + policy/policy.cpp + policy/rbf.cpp + crypto/hmac_sha256.cpp + crypto/hmac_sha512.cpp + crypto/ripemd160.cpp + crypto/sha1.cpp + crypto/sha256.cpp + crypto/sha512.cpp + crypto/chacha20.cpp + consensus/merkle.cpp + compat/glibc_compat.cpp + compat/glibc_sanity.cpp + compat/glibcxx_sanity.cpp + compat/strnlen.cpp + init.cpp + eccoind.cpp + crypto/scrypt.cpp + kernel.cpp + httprpc.cpp + httpserver.cpp + rest.cpp + rpc/rpcblockchain.cpp + rpc/rpcclient.cpp + rpc/rpcdump.cpp + rpc/rpcmining.cpp + rpc/rpcmisc.cpp + rpc/rpcnet.cpp + rpc/rpcprotocol.cpp + rpc/rpcrawtransaction.cpp + rpc/rpcserver.cpp + rpc/rpcwallet.cpp + univalue/univalue.cpp + univalue/univalue_read.cpp + univalue/univalue_write.cpp + pbkdf2.cpp + script/stakescript.cpp + signals.cpp + processtx.cpp + verifydb.cpp ) + +set(DIR_HEADERS + build.h + txdb.h + key.h + addrman.h + amount.h + arith_uint256.h + base58.h + chain/blockindex.h + bloom.h + chain/chain.h + chain/chainman.h + networks/netman.h + chain/checkpoints.h + clientversion.h + coins.h + compressor.h + dbwrapper.h + crypto/hash.h + keystore.h + main.h + merkleblock.h + messages.h + miner.h + net.h + netbase.h + noui.h + pow.h + processblock.h + processheader.h + protocol.h + pubkey.h + random.h + scheduler.h + sync.h + timedata.h + torcontrol.h + txmempool.h + uint256.h + util/util.h + fs.h + args.h + util/utilmoneystr.h + util/utilstrencodings.h + util/utiltime.h + validationinterface.h + versionbits.h + wallet/crypter.h + wallet/db.h + wallet/wallet.h + wallet/wallet_ismine.h + wallet/walletdb.h + support/cleanse.h + support/pagelocker.h + script/bitcoinconsensus.h + script/interpreter.h + script/script.h + script/script_error.h + script/sigcache.h + script/sign.h + script/standard.h + chain/block.h + tx/tx.h + policy/fees.h + policy/policy.h + policy/rbf.h + crypto/hmac_sha256.h + crypto/hmac_sha512.h + crypto/ripemd160.h + crypto/sha1.h + crypto/sha256.h + crypto/sha512.h + crypto/chacha20.h + consensus/merkle.h + init.h + crypto/scrypt.h + kernel.h + httprpc.h + httpserver.h + rpc/rpcclient.h + rpc/rpcprotocol.h + rpc/rpcserver.h + univalue/univalue.h + pbkdf2.h + script/stakescript.h + signals.h + processtx.h + verifydb.h ) + +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O2 -Wall -Wextra -Wformat -Wvla -Wformat-security -Wthread-safety-analysis -Wno-unused-parameter -Wno-self-assign -Wno-unused-local-typedef -Wno-deprecated-register -Wno-implicit-fallthrough") +add_definitions(-DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS -I/usr/local/opt/berkeley-db@4/include -DMAC_OSX) + +# Boost Dependencies +set(Boost_USE_STATIC_LIBS ON) # only find static libs +find_package( Boost REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options ) +if (${Boost_VERSION} EQUAL 104400 AND MSVC_VERSION EQUAL 1600) + # Avoid error with boost 1.44 interprocess and MSVC10 + add_definitions(-DBOOST_NO_RVALUE_REFERENCES) +endif (${Boost_VERSION} EQUAL 104400 AND MSVC_VERSION EQUAL 1600) +include_directories(${Boost_INCLUDE_DIRS}) + +# OpenSSL +find_package(OpenSSL REQUIRED) +include_directories(${OPENSSL_INCLUDE_DIR}) + +find_package(LibEvent REQUIRED) +include_directories(${LIBEVENT_INCLUDE_DIR}) + +# BerkeleyDB +set(DB_VERSION 47) +find_package(BerkeleyDB REQUIRED) +include_directories(${DB_INCLUDE_DIR}) + +# LevelDB +add_subdirectory(leveldb) + +# Sources +include_directories(${Boost_INCLUDE_DIRS} + ${OPENSSL_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/leveldb/include + ${CMAKE_CURRENT_SOURCE_DIR}/leveldb/helpers + ${CMAKE_CURRENT_SOURCE_DIR}/leveldb/helpers/memenv + ${CMAKE_CURRENT_SOURCE_DIR}/secp256k1 + ${CMAKE_CURRENT_SOURCE_DIR}/secp256k1/include + ${CMAKE_CURRENT_SOURCE_DIR}/univalue +) + + +add_library(eccoin ${DIR_HEADERS} ${DIR_SOURCES}) +target_link_libraries(eccoin leveldb + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${LIBEVENT_LIB} +) + +add_executable(eccoind ${CMAKE_CURRENT_SOURCE_DIR}/eccoind.cpp) +target_link_libraries(eccoind eccoin leveldb + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${LIBEVENT_LIB}) + + + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..8249af31 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,377 @@ +DIST_SUBDIRS = secp256k1 univalue + +AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) +AM_CXXFLAGS = $(HARDENED_CXXFLAGS) +AM_CPPFLAGS = $(HARDENED_CPPFLAGS) +EXTRA_LIBRARIES = + +BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config +BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/build $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) + +BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include +BITCOIN_INCLUDES += -I$(srcdir)/univalue + +LIBBITCOIN_SERVER=libbitcoin_server.a +LIBSECP256K1=secp256k1/libsecp256k1.la + +$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) + +# Make is not made aware of per-object dependencies to avoid limiting building parallelization +# But to build the less dependent modules first, we manually select their order here: +EXTRA_LIBRARIES += \ + libbitcoin_server.a + +BITCOIN_INCLUDES += $(BDB_CPPFLAGS) +EXTRA_LIBRARIES += libbitcoin_wallet.a + +if BUILD_BITCOIN_LIBS +lib_LTLIBRARIES = libbitcoinconsensus.la +LIBBITCOIN_CONSENSUS=libbitcoinconsensus.la +else +LIBBITCOIN_CONSENSUS= +endif + +bin_PROGRAMS = +TESTS = +BENCHMARKS = + +if BUILD_BITCOIND + bin_PROGRAMS += eccoind +endif + +.PHONY: FORCE check-symbols check-security +# bitcoin core # +BITCOIN_CORE_H = \ + addrman.h \ + amount.h \ + args.h \ + arith_uint256.h \ + base58.h \ + bloom.h \ + chain/chain.h \ + chain/chainman.h \ + chain/blockindex.h \ + chain/checkpoints.h \ + checkqueue.h \ + clientversion.h \ + coincontrol.h \ + coins.h \ + compat.h \ + compat/byteswap.h \ + compat/endian.h \ + compat/sanity.h \ + compressor.h \ + consensus/consensus.h \ + consensus/merkle.h \ + consensus/params.h \ + consensus/validation.h \ + core_io.h \ + core_memusage.h \ + crypto/hash.h \ + dbwrapper.h \ + httprpc.h \ + httpserver.h \ + init.h \ + kernel.h \ + key.h \ + keystore.h \ + limitedmap.h \ + main.h \ + messages.h \ + memusage.h \ + merkleblock.h \ + miner.h \ + net.h \ + netbase.h \ + networks/netman.h \ + networks/network.h \ + networks/networktemplate.h \ + noui.h \ + policy/fees.h \ + policy/policy.h \ + policy/rbf.h \ + pow.h \ + prevector.h \ + chain/block.h \ + tx/tx.h \ + pbkdf2.h \ + processblock.h \ + processheader.h \ + processtx.h \ + protocol.h \ + pubkey.h \ + random.h \ + reverselock.h \ + rpc/rpcclient.h \ + rpc/rpcprotocol.h \ + rpc/rpcserver.h \ + scheduler.h \ + script/interpreter.h \ + script/script.h \ + script/script_error.h \ + script/sigcache.h \ + script/sign.h \ + script/stakescript.h \ + script/standard.h \ + crypto/scrypt.h \ + serialize.h \ + signals.h \ + streams.h \ + support/allocators/secure.h \ + support/allocators/zeroafterfree.h \ + support/cleanse.h \ + support/pagelocker.h \ + sync.h \ + threadsafety.h \ + timedata.h \ + tinyformat.h \ + torcontrol.h \ + txdb.h \ + txmempool.h \ + ui_interface.h \ + uint256.h \ + undo.h \ + univalue/univalue.h \ + univalue/univalue_escapes.h \ + util/util.h \ + util/utilmoneystr.h \ + util/utilstrencodings.h \ + util/utiltime.h \ + validationinterface.h \ + verifydb.h \ + version.h \ + versionbits.h \ + wallet/crypter.h \ + wallet/db.h \ + wallet/wallet.h \ + wallet/wallet_ismine.h \ + wallet/walletdb.h + +build/build.h: FORCE + @$(MKDIR_P) $(builddir)/build + @$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/build/build.h \ + $(abs_top_srcdir) +libbitcoin_util_a-clientversion.$(OBJEXT): build/build.h + +# server: shared between bitcoin +libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIC_FLAGS) $(PIE_FLAGS) +libbitcoin_server_a_SOURCES = \ + addrman.cpp \ + bloom.cpp \ + chain/chain.cpp \ + chain/checkpoints.cpp \ + httprpc.cpp \ + httpserver.cpp \ + init.cpp \ + dbwrapper.cpp \ + kernel.cpp \ + main.cpp \ + merkleblock.cpp \ + miner.cpp \ + net.cpp \ + noui.cpp \ + policy/fees.cpp \ + policy/policy.cpp \ + pow.cpp \ + rest.cpp \ + rpc/rpcblockchain.cpp \ + rpc/rpcmining.cpp \ + rpc/rpcmisc.cpp \ + rpc/rpcnet.cpp \ + rpc/rpcrawtransaction.cpp \ + rpc/rpcserver.cpp \ + script/sigcache.cpp \ + timedata.cpp \ + torcontrol.cpp \ + txdb.cpp \ + txmempool.cpp \ + validationinterface.cpp \ + versionbits.cpp \ + amount.cpp \ + arith_uint256.cpp \ + base58.cpp \ + chain/chainman.cpp \ + coins.cpp \ + compressor.cpp \ + consensus/merkle.cpp \ + core_read.cpp \ + core_write.cpp \ + crypto/hash.cpp \ + key.cpp \ + keystore.cpp \ + netbase.cpp \ + chain/block.cpp \ + chain/blockindex.cpp \ + processblock.cpp \ + processheader.cpp \ + processtx.cpp \ + tx/tx.cpp \ + protocol.cpp \ + pubkey.cpp \ + scheduler.cpp \ + pbkdf2.cpp \ + script/interpreter.cpp \ + script/script.cpp \ + script/script_error.cpp \ + script/sign.cpp \ + script/standard.cpp \ + script/stakescript.cpp \ + args.cpp \ + support/pagelocker.cpp \ + chain/chainman.cpp \ + clientversion.cpp \ + compat/glibc_sanity.cpp \ + compat/glibcxx_sanity.cpp \ + compat/strnlen.cpp \ + networks/netman.cpp \ + messages.cpp \ + random.cpp \ + rpc/rpcprotocol.cpp \ + support/cleanse.cpp \ + sync.cpp \ + uint256.cpp \ + univalue/univalue.cpp \ + univalue/univalue_read.cpp \ + univalue/univalue_write.cpp \ + util/util.cpp \ + util/utilmoneystr.cpp \ + util/utilstrencodings.cpp \ + util/utiltime.cpp \ + verifydb.cpp \ + signals.cpp \ + crypto/chacha20.cpp \ + crypto/chacha20.h \ + crypto/common.h \ + crypto/hmac_sha256.cpp \ + crypto/hmac_sha256.h \ + crypto/hmac_sha512.cpp \ + crypto/hmac_sha512.h \ + crypto/ripemd160.cpp \ + crypto/ripemd160.h \ + crypto/sha1.cpp \ + crypto/sha1.h \ + crypto/sha256.cpp \ + crypto/sha256.h \ + crypto/sha512.cpp \ + crypto/sha512.h \ + crypto/scrypt.cpp \ + wallet/crypter.cpp \ + wallet/db.cpp \ + rpc/rpcdump.cpp \ + rpc/rpcwallet.cpp \ + wallet/wallet.cpp \ + wallet/wallet_ismine.cpp \ + wallet/walletdb.cpp \ + policy/rbf.cpp \ + rpc/rpcclient.cpp \ + $(BITCOIN_CORE_H) + +if GLIBC_BACK_COMPAT +libbitcoin_server_a_SOURCES += compat/glibc_compat.cpp +endif + +# bitcoin binary # +eccoind_SOURCES = eccoind.cpp +eccoind_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +eccoind_CXXFLAGS = $(AM_CXXFLAGS) $(PIC_FLAGS) $(PIE_FLAGS) +eccoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) + +eccoind_LDADD = \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBLEVELDB) \ + $(LIBMEMENV) \ + $(LIBSECP256K1) + +eccoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) + +# bitcoinconsensus library # +if BUILD_BITCOIN_LIBS +include_HEADERS = script/bitcoinconsensus.h +libbitcoinconsensus_la_SOURCES = \ + crypto/hmac_sha512.cpp \ + crypto/ripemd160.cpp \ + crypto/sha1.cpp \ + crypto/sha256.cpp \ + crypto/sha512.cpp \ + crypto/hash.cpp \ + pubkey.cpp \ + script/bitcoinconsensus.cpp \ + script/interpreter.cpp \ + script/script.cpp \ + uint256.cpp \ + util/utilstrencodings.cpp + +if GLIBC_BACK_COMPAT + libbitcoinconsensus_la_SOURCES += compat/glibc_compat.cpp +endif + +libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) +libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1) -lcrypto +libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/build -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL $(BITCOIN_INCLUDES) +libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIC_FLAGS) $(PIE_FLAGS) + +endif +# + +CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a +CLEANFILES += *.gcda *.gcno +CLEANFILES += compat/*.gcda compat/*.gcno +CLEANFILES += consensus/*.gcda consensus/*.gcno +CLEANFILES += crypto/*.gcda crypto/*.gcno +CLEANFILES += policy/*.gcda policy/*.gcno +CLEANFILES += primitives/*.gcda primitives/*.gcno +CLEANFILES += script/*.gcda script/*.gcno +CLEANFILES += support/*.gcda support/*.gcno +CLEANFILES += univalue/*.gcda univalue/*.gcno +CLEANFILES += wallet/*.gcda wallet/*.gcno +CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno + +DISTCLEANFILES = build/build.h + +EXTRA_DIST = leveldb + +clean-local: + -$(MAKE) -C leveldb clean + -$(MAKE) -C secp256k1 clean + -$(MAKE) -C univalue clean + -rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno + -rm -f config.h + +.rc.o: + @test -f $(WINDRES) + $(AM_V_GEN) $(WINDRES) -DWINDRES_PREPROC -i $< -o $@ + +.mm.o: + $(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(AM_CXXFLAGS) $(PIC_FLAGS) $(PIE_FLAGS) $(CXXFLAGS) -c -o $@ $< + +check-symbols: $(bin_PROGRAMS) +if GLIBC_BACK_COMPAT + @echo "Checking glibc back compat..." + $(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py < $(bin_PROGRAMS) +endif + +check-security: $(bin_PROGRAMS) +if HARDEN + @echo "Checking binary security..." + $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS) +endif + +%.pb.cc %.pb.h: %.proto + @test -f $(PROTOC) + $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $( $@ + @echo "static unsigned const char $(*F)[] = {" >> $@ + @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@ + @echo "};};" >> $@ + @echo "Generated $@" + +%.raw.h: %.raw + @$(MKDIR_P) $(@D) + @echo "namespace alert_tests{" > $@ + @echo "static unsigned const char $(*F)[] = {" >> $@ + @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@ + @echo "};};" >> $@ + @echo "Generated $@" diff --git a/src/addrman.cpp b/src/addrman.cpp index 078b9e16..adfaa708 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -1,105 +1,107 @@ // Copyright (c) 2012 Pieter Wuille +// Copyright (c) 2012-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 "addrman.h" -#include "hash.h" +#include "crypto/hash.h" #include "serialize.h" #include "streams.h" -int CAddrInfo::GetTriedBucket(const uint256& nKey) const -{ - uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetHash().GetCheapHash(); - uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetHash().GetCheapHash(); +int CAddrInfo::GetTriedBucket(const uint256 &nKey) const { + uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()) + .GetHash() + .GetCheapHash(); + uint64_t hash2 = + (CHashWriter(SER_GETHASH, 0) + << nKey << GetGroup() << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)) + .GetHash() + .GetCheapHash(); return hash2 % ADDRMAN_TRIED_BUCKET_COUNT; } -int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src) const -{ - std::vector vchSourceGroupKey = src.GetGroup(); - uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << vchSourceGroupKey).GetHash().GetCheapHash(); - uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetHash().GetCheapHash(); +int CAddrInfo::GetNewBucket(const uint256 &nKey, const CNetAddr &src) const { + std::vector vchSourceGroupKey = src.GetGroup(); + uint64_t hash1 = + (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << vchSourceGroupKey) + .GetHash() + .GetCheapHash(); + uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) + << nKey << vchSourceGroupKey + << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)) + .GetHash() + .GetCheapHash(); return hash2 % ADDRMAN_NEW_BUCKET_COUNT; } -int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const -{ - uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << GetKey()).GetHash().GetCheapHash(); +int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, + int nBucket) const { + uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') + << nBucket << GetKey()) + .GetHash() + .GetCheapHash(); return hash1 % ADDRMAN_BUCKET_SIZE; } -bool CAddrInfo::IsTerrible(int64_t nNow) const -{ - if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute - return false; +bool CAddrInfo::IsTerrible(int64_t nNow) const { + // never remove things tried in the last minute + if (nLastTry && nLastTry >= nNow - 60) return false; - if (nTime > nNow + 10 * 60) // came in a flying DeLorean - return true; + // came in a flying DeLorean + if (nTime > nNow + 10 * 60) return true; - if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) // not seen in recent history + // not seen in recent history + if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) return true; - if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success - return true; + // tried N times and never a success + if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) return true; - if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week + if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && + nAttempts >= + ADDRMAN_MAX_FAILURES) // N successive failures in the last week return true; return false; } -double CAddrInfo::GetChance(int64_t nNow) const -{ +double CAddrInfo::GetChance(int64_t nNow) const { double fChance = 1.0; - - int64_t nSinceLastSeen = nNow - nTime; - int64_t nSinceLastTry = nNow - nLastTry; - - if (nSinceLastSeen < 0) - nSinceLastSeen = 0; - if (nSinceLastTry < 0) - nSinceLastTry = 0; + int64_t nSinceLastTry = std::max(nNow - nLastTry, 0); // deprioritize very recent attempts away - if (nSinceLastTry < 60 * 10) - fChance *= 0.01; + if (nSinceLastTry < 60 * 10) fChance *= 0.01; - // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages. + // deprioritize 66% after each failed attempt, but at most 1/28th to avoid + // the search taking forever or overly penalizing outages. fChance *= pow(0.66, std::min(nAttempts, 8)); return fChance; } -CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId) -{ +CAddrInfo *CAddrMan::Find(const CNetAddr &addr, int *pnId) { std::map::iterator it = mapAddr.find(addr); - if (it == mapAddr.end()) - return NULL; - if (pnId) - *pnId = (*it).second; + if (it == mapAddr.end()) return nullptr; + if (pnId) *pnId = (*it).second; std::map::iterator it2 = mapInfo.find((*it).second); - if (it2 != mapInfo.end()) - return &(*it2).second; - return NULL; + if (it2 != mapInfo.end()) return &(*it2).second; + return nullptr; } -CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId) -{ +CAddrInfo *CAddrMan::Create(const CAddress &addr, const CNetAddr &addrSource, + int *pnId) { int nId = nIdCount++; mapInfo[nId] = CAddrInfo(addr, addrSource); mapAddr[addr] = nId; mapInfo[nId].nRandomPos = vRandom.size(); vRandom.push_back(nId); - if (pnId) - *pnId = nId; + if (pnId) *pnId = nId; return &mapInfo[nId]; } -void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) -{ - if (nRndPos1 == nRndPos2) - return; +void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) { + if (nRndPos1 == nRndPos2) return; assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size()); @@ -116,10 +118,9 @@ void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) vRandom[nRndPos2] = nId1; } -void CAddrMan::Delete(int nId) -{ +void CAddrMan::Delete(int nId) { assert(mapInfo.count(nId) != 0); - CAddrInfo& info = mapInfo[nId]; + CAddrInfo &info = mapInfo[nId]; assert(!info.fInTried); assert(info.nRefCount == 0); @@ -130,12 +131,11 @@ void CAddrMan::Delete(int nId) nNew--; } -void CAddrMan::ClearNew(int nUBucket, int nUBucketPos) -{ +void CAddrMan::ClearNew(int nUBucket, int nUBucketPos) { // if there is an entry in the specified bucket, delete it. if (vvNew[nUBucket][nUBucketPos] != -1) { int nIdDelete = vvNew[nUBucket][nUBucketPos]; - CAddrInfo& infoDelete = mapInfo[nIdDelete]; + CAddrInfo &infoDelete = mapInfo[nIdDelete]; assert(infoDelete.nRefCount > 0); infoDelete.nRefCount--; vvNew[nUBucket][nUBucketPos] = -1; @@ -145,8 +145,7 @@ void CAddrMan::ClearNew(int nUBucket, int nUBucketPos) } } -void CAddrMan::MakeTried(CAddrInfo& info, int nId) -{ +void CAddrMan::MakeTried(CAddrInfo &info, int nId) { // remove the entry from all new buckets for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) { int pos = info.GetBucketPosition(nKey, true, bucket); @@ -163,12 +162,13 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId) int nKBucket = info.GetTriedBucket(nKey); int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket); - // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there). + // first make space to add it (the existing tried entry there is moved to + // new, deleting whatever is there). if (vvTried[nKBucket][nKBucketPos] != -1) { // find an item to evict int nIdEvict = vvTried[nKBucket][nKBucketPos]; assert(mapInfo.count(nIdEvict) == 1); - CAddrInfo& infoOld = mapInfo[nIdEvict]; + CAddrInfo &infoOld = mapInfo[nIdEvict]; // Remove the to-be-evicted item from the tried set. infoOld.fInTried = false; @@ -193,20 +193,21 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId) info.fInTried = true; } -void CAddrMan::Good_(const CService& addr, int64_t nTime) -{ +void CAddrMan::Good_(const CService &addr, int64_t nTime) { int nId; - CAddrInfo* pinfo = Find(addr, &nId); + + nLastGood = nTime; + + CAddrInfo *pinfo = Find(addr, &nId); // if not found, bail out - if (!pinfo) - return; + if (!pinfo) return; - CAddrInfo& info = *pinfo; + CAddrInfo &info = *pinfo; - // check whether we are talking about the exact same CService (including same port) - if (info != addr) - return; + // check whether we are talking about the exact same CService (including + // same port) + if (info != addr) return; // update info info.nLastSuccess = nTime; @@ -216,11 +217,10 @@ void CAddrMan::Good_(const CService& addr, int64_t nTime) // currently-connected peers. // if it is already in the tried set, don't do anything else - if (info.fInTried) - return; + if (info.fInTried) return; // find a bucket it is in now - int nRnd = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT); + int nRnd = RandomInt(ADDRMAN_NEW_BUCKET_COUNT); int nUBucket = -1; for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) { int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT; @@ -233,8 +233,7 @@ void CAddrMan::Good_(const CService& addr, int64_t nTime) // if no bucket is found, something bad happened; // TODO: maybe re-add the node, but for now, just bail out - if (nUBucket == -1) - return; + if (nUBucket == -1) return; LogPrint("addrman", "Moving %s to tried\n", addr.ToString()); @@ -242,46 +241,51 @@ void CAddrMan::Good_(const CService& addr, int64_t nTime) MakeTried(info, nId); } -bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) -{ - if (!addr.IsRoutable()) - return false; +bool CAddrMan::Add_(const CAddress &addr, const CNetAddr &source, + int64_t nTimePenalty) { + if (!addr.IsRoutable()) return false; bool fNew = false; int nId; - CAddrInfo* pinfo = Find(addr, &nId); + CAddrInfo *pinfo = Find(addr, &nId); + + // Do not set a penalty for a source's self-announcement + if (addr == source) { + nTimePenalty = 0; + } if (pinfo) { // periodically update nTime bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); - if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) + if (addr.nTime && + (!pinfo->nTime || + pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty); // add services - pinfo->nServices |= addr.nServices; + pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices); // do not update if no new information is present if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime)) return false; // do not update if the entry was already in the "tried" table - if (pinfo->fInTried) - return false; + if (pinfo->fInTried) return false; // do not update if the max reference count is reached - if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS) - return false; + if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS) return false; - // stochastic test: previous nRefCount == N: 2^N times harder to increase it + // stochastic test: previous nRefCount == N: 2^N times harder to + // increase it int nFactor = 1; for (int n = 0; n < pinfo->nRefCount; n++) nFactor *= 2; - if (nFactor > 1 && (GetRandInt(nFactor) != 0)) - return false; + if (nFactor > 1 && (RandomInt(nFactor) != 0)) return false; } else { pinfo = Create(addr, source, &nId); - pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); + pinfo->nTime = + std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); nNew++; fNew = true; } @@ -291,8 +295,9 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP if (vvNew[nUBucket][nUBucketPos] != nId) { bool fInsert = vvNew[nUBucket][nUBucketPos] == -1; if (!fInsert) { - CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]]; - if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) { + CAddrInfo &infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]]; + if (infoExisting.IsTerrible() || + (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) { // Overwrite the existing new table entry. fInsert = true; } @@ -310,66 +315,79 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP return fNew; } -void CAddrMan::Attempt_(const CService& addr, int64_t nTime) -{ - CAddrInfo* pinfo = Find(addr); +void CAddrMan::Attempt_(const CService &addr, bool fCountFailure, + int64_t nTime) { + CAddrInfo *pinfo = Find(addr); // if not found, bail out - if (!pinfo) - return; + if (!pinfo) return; - CAddrInfo& info = *pinfo; + CAddrInfo &info = *pinfo; - // check whether we are talking about the exact same CService (including same port) - if (info != addr) - return; + // check whether we are talking about the exact same CService (including + // same port) + if (info != addr) return; // update info info.nLastTry = nTime; - info.nAttempts++; + if (fCountFailure && info.nLastCountAttempt < nLastGood) { + info.nLastCountAttempt = nTime; + info.nAttempts++; + } } -CAddrInfo CAddrMan::Select_(bool newOnly) -{ - if (size() == 0) - return CAddrInfo(); +CAddrInfo CAddrMan::Select_(bool newOnly) { + if (size() == 0) return CAddrInfo(); - if (newOnly && nNew == 0) - return CAddrInfo(); + if (newOnly && nNew == 0) return CAddrInfo(); // Use a 50% chance for choosing between tried and new table entries. - if (!newOnly && - (nTried > 0 && (nNew == 0 || GetRandInt(2) == 0))) { + if (!newOnly && (nTried > 0 && (nNew == 0 || RandomInt(2) == 0))) { // use a tried node double fChanceFactor = 1.0; while (1) { - int nKBucket = GetRandInt(ADDRMAN_TRIED_BUCKET_COUNT); - int nKBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE); + int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT); + int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE); while (vvTried[nKBucket][nKBucketPos] == -1) { - nKBucket = (nKBucket + insecure_rand()) % ADDRMAN_TRIED_BUCKET_COUNT; - nKBucketPos = (nKBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE; + nKBucket = + (nKBucket + + insecure_rand.randbits(ADDRMAN_TRIED_BUCKET_COUNT_LOG2)) % + ADDRMAN_TRIED_BUCKET_COUNT; + nKBucketPos = + (nKBucketPos + + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % + ADDRMAN_BUCKET_SIZE; } int nId = vvTried[nKBucket][nKBucketPos]; assert(mapInfo.count(nId) == 1); - CAddrInfo& info = mapInfo[nId]; - if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) + CAddrInfo &info = mapInfo[nId]; + if (RandomInt(1 << 30) < + fChanceFactor * info.GetChance() * (1 << 30)) { return info; + } fChanceFactor *= 1.2; } } else { // use a new node double fChanceFactor = 1.0; while (1) { - int nUBucket = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT); - int nUBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE); + int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT); + int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE); while (vvNew[nUBucket][nUBucketPos] == -1) { - nUBucket = (nUBucket + insecure_rand()) % ADDRMAN_NEW_BUCKET_COUNT; - nUBucketPos = (nUBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE; + nUBucket = + (nUBucket + + insecure_rand.randbits(ADDRMAN_NEW_BUCKET_COUNT_LOG2)) % + ADDRMAN_NEW_BUCKET_COUNT; + nUBucketPos = + (nUBucketPos + + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % + ADDRMAN_BUCKET_SIZE; } int nId = vvNew[nUBucket][nUBucketPos]; assert(mapInfo.count(nId) == 1); - CAddrInfo& info = mapInfo[nId]; - if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) + CAddrInfo &info = mapInfo[nId]; + if (RandomInt(1 << 30) < + fChanceFactor * info.GetChance() * (1 << 30)) return info; fChanceFactor *= 1.2; } @@ -377,120 +395,121 @@ CAddrInfo CAddrMan::Select_(bool newOnly) } #ifdef DEBUG_ADDRMAN -int CAddrMan::Check_() -{ +int CAddrMan::Check_() { std::set setTried; std::map mapNew; - if (vRandom.size() != nTried + nNew) - return -7; + if (vRandom.size() != nTried + nNew) return -7; - for (std::map::iterator it = mapInfo.begin(); it != mapInfo.end(); it++) { + for (std::map::iterator it = mapInfo.begin(); + it != mapInfo.end(); it++) { int n = (*it).first; - CAddrInfo& info = (*it).second; + CAddrInfo &info = (*it).second; if (info.fInTried) { - if (!info.nLastSuccess) - return -1; - if (info.nRefCount) - return -2; + if (!info.nLastSuccess) return -1; + if (info.nRefCount) return -2; setTried.insert(n); } else { - if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS) + if (info.nRefCount < 0 || + info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS) return -3; - if (!info.nRefCount) - return -4; + if (!info.nRefCount) return -4; mapNew[n] = info.nRefCount; } - if (mapAddr[info] != n) - return -5; - if (info.nRandomPos < 0 || info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n) + if (mapAddr[info] != n) return -5; + if (info.nRandomPos < 0 || info.nRandomPos >= vRandom.size() || + vRandom[info.nRandomPos] != n) return -14; - if (info.nLastTry < 0) - return -6; - if (info.nLastSuccess < 0) - return -8; + if (info.nLastTry < 0) return -6; + if (info.nLastSuccess < 0) return -8; } - if (setTried.size() != nTried) - return -9; - if (mapNew.size() != nNew) - return -10; + if (setTried.size() != nTried) return -9; + if (mapNew.size() != nNew) return -10; for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) { for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { - if (vvTried[n][i] != -1) { - if (!setTried.count(vvTried[n][i])) - return -11; - if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey) != n) - return -17; - if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i) - return -18; - setTried.erase(vvTried[n][i]); - } + if (vvTried[n][i] != -1) { + if (!setTried.count(vvTried[n][i])) return -11; + if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey) != n) + return -17; + if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != + i) + return -18; + setTried.erase(vvTried[n][i]); + } } } for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) { for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { if (vvNew[n][i] != -1) { - if (!mapNew.count(vvNew[n][i])) - return -12; + if (!mapNew.count(vvNew[n][i])) return -12; if (mapInfo[vvNew[n][i]].GetBucketPosition(nKey, true, n) != i) return -19; - if (--mapNew[vvNew[n][i]] == 0) - mapNew.erase(vvNew[n][i]); + if (--mapNew[vvNew[n][i]] == 0) mapNew.erase(vvNew[n][i]); } } } - if (setTried.size()) - return -13; - if (mapNew.size()) - return -15; - if (nKey.IsNull()) - return -16; + if (setTried.size()) return -13; + if (mapNew.size()) return -15; + if (nKey.IsNull()) return -16; return 0; } #endif -void CAddrMan::GetAddr_(std::vector& vAddr) -{ +void CAddrMan::GetAddr_(std::vector &vAddr) { unsigned int nNodes = ADDRMAN_GETADDR_MAX_PCT * vRandom.size() / 100; - if (nNodes > ADDRMAN_GETADDR_MAX) - nNodes = ADDRMAN_GETADDR_MAX; + if (nNodes > ADDRMAN_GETADDR_MAX) nNodes = ADDRMAN_GETADDR_MAX; // gather a list of random nodes, skipping those of low quality for (unsigned int n = 0; n < vRandom.size(); n++) { - if (vAddr.size() >= nNodes) - break; + if (vAddr.size() >= nNodes) break; - int nRndPos = GetRandInt(vRandom.size() - n) + n; + int nRndPos = RandomInt(vRandom.size() - n) + n; SwapRandom(n, nRndPos); assert(mapInfo.count(vRandom[n]) == 1); - const CAddrInfo& ai = mapInfo[vRandom[n]]; - if (!ai.IsTerrible()) - vAddr.push_back(ai); + const CAddrInfo &ai = mapInfo[vRandom[n]]; + if (!ai.IsTerrible()) vAddr.push_back(ai); } } -void CAddrMan::Connected_(const CService& addr, int64_t nTime) -{ - CAddrInfo* pinfo = Find(addr); +void CAddrMan::Connected_(const CService &addr, int64_t nTime) { + CAddrInfo *pinfo = Find(addr); // if not found, bail out - if (!pinfo) - return; + if (!pinfo) return; - CAddrInfo& info = *pinfo; + CAddrInfo &info = *pinfo; - // check whether we are talking about the exact same CService (including same port) - if (info != addr) - return; + // check whether we are talking about the exact same CService (including + // same port) + if (info != addr) return; // update info int64_t nUpdateInterval = 20 * 60; - if (nTime - info.nTime > nUpdateInterval) - info.nTime = nTime; + if (nTime - info.nTime > nUpdateInterval) info.nTime = nTime; +} + +void CAddrMan::SetServices_(const CService &addr, ServiceFlags nServices) { + CAddrInfo *pinfo = Find(addr); + + // if not found, bail out + if (!pinfo) return; + + CAddrInfo &info = *pinfo; + + // check whether we are talking about the exact same CService (including + // same port) + if (info != addr) return; + + // update info + info.nServices = nServices; +} + +int CAddrMan::RandomInt(int nMax) { + return GetRandInt(nMax); } diff --git a/src/addrman.h b/src/addrman.h index 45c39af6..2b482cd8 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -10,7 +10,7 @@ #include "random.h" #include "sync.h" #include "timedata.h" -#include "util.h" +#include "util/util.h" #include #include @@ -20,14 +20,15 @@ /** * Extended statistics about a CAddress */ -class CAddrInfo : public CAddress -{ - +class CAddrInfo : public CAddress { public: //! last try whatsoever by us (memory only) int64_t nLastTry; + //! last counted attempt (memory only) + int64_t nLastCountAttempt; + private: //! where knowledge about this address first came from CNetAddr source; @@ -50,102 +51,115 @@ class CAddrInfo : public CAddress friend class CAddrMan; public: - - ADD_SERIALIZE_METHODS + ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(*(CAddress*)this); + inline void SerializationOp(Stream &s, Operation ser_action) { + READWRITE(*(CAddress *)this); READWRITE(source); READWRITE(nLastSuccess); READWRITE(nAttempts); } - void Init() - { + void Init() { nLastSuccess = 0; nLastTry = 0; + nLastCountAttempt = 0; nAttempts = 0; nRefCount = 0; fInTried = false; nRandomPos = -1; } - CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource) - { + CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) + : CAddress(addrIn), source(addrSource) { Init(); } - CAddrInfo() : CAddress(), source() - { - Init(); - } + CAddrInfo() : CAddress(), source() { Init(); } //! Calculate in which "tried" bucket this entry belongs int GetTriedBucket(const uint256 &nKey) const; - //! Calculate in which "new" bucket this entry belongs, given a certain source - int GetNewBucket(const uint256 &nKey, const CNetAddr& src) const; + //! Calculate in which "new" bucket this entry belongs, given a certain + //! source + int GetNewBucket(const uint256 &nKey, const CNetAddr &src) const; - //! Calculate in which "new" bucket this entry belongs, using its default source - int GetNewBucket(const uint256 &nKey) const - { + //! Calculate in which "new" bucket this entry belongs, using its default + //! source + int GetNewBucket(const uint256 &nKey) const { return GetNewBucket(nKey, source); } //! Calculate in which position of a bucket to store this entry. int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const; - //! Determine whether the statistics about this entry are bad enough so that it can just be deleted + //! Determine whether the statistics about this entry are bad enough so that + //! it can just be deleted bool IsTerrible(int64_t nNow = GetAdjustedTime()) const; - //! Calculate the relative chance this entry should be given when selecting nodes to connect to + //! Calculate the relative chance this entry should be given when selecting + //! nodes to connect to double GetChance(int64_t nNow = GetAdjustedTime()) const; - }; /** Stochastic address manager * * Design goals: - * * Keep the address tables in-memory, and asynchronously dump the entire table to peers.dat. - * * Make sure no (localized) attacker can fill the entire table with his nodes/addresses. + * * Keep the address tables in-memory, and asynchronously dump the entire + * table to peers.dat. + * * Make sure no (localized) attacker can fill the entire table with his + * nodes/addresses. * * To that end: * * Addresses are organized into buckets. * * Addresses that have not yet been tried go into 1024 "new" buckets. - * * Based on the address range (/16 for IPv4) of the source of information, 64 buckets are selected at random. - * * The actual bucket is chosen from one of these, based on the range in which the address itself is located. - * * One single address can occur in up to 8 different buckets to increase selection chances for addresses that - * are seen frequently. The chance for increasing this multiplicity decreases exponentially. - * * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen + * * Based on the address range (/16 for IPv4) of the source of + * information, 64 buckets are selected at random. + * * The actual bucket is chosen from one of these, based on the range in + * which the address itself is located. + * * One single address can occur in up to 8 different buckets to increase + * selection chances for addresses that + * are seen frequently. The chance for increasing this multiplicity + * decreases exponentially. + * * When adding a new address to a full bucket, a randomly chosen entry + * (with a bias favoring less recently seen * ones) is removed from it first. - * * Addresses of nodes that are known to be accessible go into 256 "tried" buckets. + * * Addresses of nodes that are known to be accessible go into 256 "tried" + * buckets. * * Each address range selects at random 8 of these buckets. - * * The actual bucket is chosen from one of these, based on the full address. - * * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently + * * The actual bucket is chosen from one of these, based on the full + * address. + * * When adding a new good address to a full bucket, a randomly chosen + * entry (with a bias favoring less recently * tried ones) is evicted from it, back to the "new" buckets. - * * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not + * * Bucket selection is based on cryptographic hashing, using a + * randomly-generated 256-bit key, which should not * be observable by adversaries. - * * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive) + * * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN + * will introduce frequent (and expensive) * consistency checks for the entire data structure. */ //! total number of buckets for tried addresses -#define ADDRMAN_TRIED_BUCKET_COUNT 256 +#define ADDRMAN_TRIED_BUCKET_COUNT_LOG2 8 //! total number of buckets for new addresses -#define ADDRMAN_NEW_BUCKET_COUNT 1024 +#define ADDRMAN_NEW_BUCKET_COUNT_LOG2 10 //! maximum allowed number of entries in buckets for new and tried addresses -#define ADDRMAN_BUCKET_SIZE 64 +#define ADDRMAN_BUCKET_SIZE_LOG2 6 -//! over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread +//! over how many buckets entries with tried addresses from a single group (/16 +//! for IPv4) are spread #define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8 -//! over how many buckets entries with new addresses originating from a single group are spread +//! over how many buckets entries with new addresses originating from a single +//! group are spread #define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 64 -//! in how many buckets for entries with new addresses a single address may occur +//! in how many buckets for entries with new addresses a single address may +//! occur #define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8 //! how old addresses can maximally be @@ -166,18 +180,19 @@ class CAddrInfo : public CAddress //! the maximum number of nodes to return in a getaddr call #define ADDRMAN_GETADDR_MAX 2500 -/** - * Stochastical (IP) address manager +//! Convenience +#define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2) +#define ADDRMAN_NEW_BUCKET_COUNT (1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2) +#define ADDRMAN_BUCKET_SIZE (1 << ADDRMAN_BUCKET_SIZE_LOG2) + +/** + * Stochastical (IP) address manager */ -class CAddrMan -{ +class CAddrMan { private: //! critical section to protect the inner data structures mutable CCriticalSection cs; - //! secret key to randomize bucket select with - uint256 nKey; - //! last used nId int nIdCount; @@ -202,39 +217,55 @@ class CAddrMan //! list of "new" buckets int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]; + //! last time Good was called (memory only) + int64_t nLastGood; + protected: + //! secret key to randomize bucket select with + uint256 nKey; + + //! Source of random numbers for randomization in inner loops + FastRandomContext insecure_rand; //! Find an entry. - CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL); + CAddrInfo *Find(const CNetAddr &addr, int *pnId = nullptr); //! find an entry, creating it if necessary. //! nTime and nServices of the found node are updated, if necessary. - CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = NULL); + CAddrInfo *Create(const CAddress &addr, const CNetAddr &addrSource, + int *pnId = nullptr); //! Swap two elements in vRandom. void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2); //! Move an entry from the "new" table(s) to the "tried" table - void MakeTried(CAddrInfo& info, int nId); + void MakeTried(CAddrInfo &info, int nId); //! Delete an entry. It must not be in tried, and have refcount 0. void Delete(int nId); - //! Clear a position in a "new" table. This is the only place where entries are actually deleted. + //! Clear a position in a "new" table. This is the only place where entries + //! are actually deleted. void ClearNew(int nUBucket, int nUBucketPos); //! Mark an entry "good", possibly moving it from "new" to "tried". void Good_(const CService &addr, int64_t nTime); //! Add an entry to the "new" table. - bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty); + bool Add_(const CAddress &addr, const CNetAddr &source, + int64_t nTimePenalty); //! Mark an entry as attempted to connect. - void Attempt_(const CService &addr, int64_t nTime); + void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime); - //! Select an address to connect to, if newOnly is set to true, only the new table is selected from. + //! Select an address to connect to, if newOnly is set to true, only the new + //! table is selected from. CAddrInfo Select_(bool newOnly); + //! Wraps GetRandInt to allow tests to override RandomInt and make it + //! determinismistic. + virtual int RandomInt(int nMax); + #ifdef DEBUG_ADDRMAN //! Perform consistency check. Returns an error code or zero. int Check_(); @@ -246,11 +277,15 @@ class CAddrMan //! Mark an entry as currently-connected-to. void Connected_(const CService &addr, int64_t nTime); + //! Update an entry's service bits. + void SetServices_(const CService &addr, ServiceFlags nServices); + public: /** * serialized format: * * version byte (currently 1) - * * 0x20 + nKey (serialized as if it were a vector, for backward compatibility) + * * 0x20 + nKey (serialized as if it were a vector, for backward + * compatibility) * * nNew * * nTried * * number of "new" buckets XOR 2**30 @@ -260,30 +295,29 @@ class CAddrMan * * number of elements * * for each element: index * - * 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it - * as incompatible. This is necessary because it did not check the version number on - * deserialization. + * 2**30 is xorred with the number of buckets to make addrman deserializer + * v0 detect it as incompatible. This is necessary because it did not check + * the version number on deserialization. * * Notice that vvTried, mapAddr and vVector are never encoded explicitly; * they are instead reconstructed from the other information. * - * vvNew is serialized, but only used if ADDRMAN_UNKNOWN_BUCKET_COUNT didn't change, - * otherwise it is reconstructed as well. + * vvNew is serialized, but only used if ADDRMAN_UNKNOWN_BUCKET_COUNT didn't + * change, otherwise it is reconstructed as well. * - * This format is more complex, but significantly smaller (at most 1.5 MiB), and supports - * changes to the ADDRMAN_ parameters without breaking the on-disk structure. + * This format is more complex, but significantly smaller (at most 1.5 MiB), + * and supports changes to the ADDRMAN_ parameters without breaking the + * on-disk structure. * - * We don't use ADD_SERIALIZE_METHODS since the serialization and deserialization code has - * very little in common. + * We don't use ADD_SERIALIZE_METHODS since the serialization and + * deserialization code has very little in common. */ - template - void Serialize(Stream &s, int nType, int nVersionDummy) const - { + template void Serialize(Stream &s) const { LOCK(cs); - unsigned char nVersion = 1; + uint8_t nVersion = 1; s << nVersion; - s << ((unsigned char)32); + s << uint8_t(32); s << nKey; s << nNew; s << nTried; @@ -292,20 +326,24 @@ class CAddrMan s << nUBuckets; std::map mapUnkIds; int nIds = 0; - for (std::map::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) { + for (std::map::const_iterator it = mapInfo.begin(); + it != mapInfo.end(); it++) { mapUnkIds[(*it).first] = nIds; const CAddrInfo &info = (*it).second; if (info.nRefCount) { - assert(nIds != nNew); // this means nNew was wrong, oh ow + // this means nNew was wrong, oh ow + assert(nIds != nNew); s << info; nIds++; } } nIds = 0; - for (std::map::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) { + for (std::map::const_iterator it = mapInfo.begin(); + it != mapInfo.end(); it++) { const CAddrInfo &info = (*it).second; if (info.fInTried) { - assert(nIds != nTried); // this means nTried was wrong, oh ow + // this means nTried was wrong, oh ow + assert(nIds != nTried); s << info; nIds++; } @@ -313,8 +351,7 @@ class CAddrMan for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) { int nSize = 0; for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { - if (vvNew[bucket][i] != -1) - nSize++; + if (vvNew[bucket][i] != -1) nSize++; } s << nSize; for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { @@ -326,18 +363,18 @@ class CAddrMan } } - template - void Unserialize(Stream& s, int nType, int nVersionDummy) - { + template void Unserialize(Stream &s) { LOCK(cs); Clear(); - unsigned char nVersion; + uint8_t nVersion; s >> nVersion; - unsigned char nKeySize; + uint8_t nKeySize; s >> nKeySize; - if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization"); + if (nKeySize != 32) + throw std::ios_base::failure( + "Incorrect keysize in addrman deserialization"); s >> nKey; s >> nNew; s >> nTried; @@ -347,6 +384,16 @@ class CAddrMan nUBuckets ^= (1 << 30); } + if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) { + throw std::ios_base::failure( + "Corrupt CAddrMan serialization, nNew exceeds limit."); + } + + if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) { + throw std::ios_base::failure( + "Corrupt CAddrMan serialization, nTried exceeds limit."); + } + // Deserialize entries from the new table. for (int n = 0; n < nNew; n++) { CAddrInfo &info = mapInfo[n]; @@ -355,8 +402,9 @@ class CAddrMan info.nRandomPos = vRandom.size(); vRandom.push_back(n); if (nVersion != 1 || nUBuckets != ADDRMAN_NEW_BUCKET_COUNT) { - // In case the new table data cannot be used (nVersion unknown, or bucket count wrong), - // immediately try to give them a reference based on their primary source address. + // In case the new table data cannot be used (nVersion unknown, + // or bucket count wrong), immediately try to give them a + // reference based on their primary source address. int nUBucket = info.GetNewBucket(nKey); int nUBucketPos = info.GetBucketPosition(nKey, true, nUBucket); if (vvNew[nUBucket][nUBucketPos] == -1) { @@ -397,8 +445,12 @@ class CAddrMan s >> nIndex; if (nIndex >= 0 && nIndex < nNew) { CAddrInfo &info = mapInfo[nIndex]; - int nUBucketPos = info.GetBucketPosition(nKey, true, bucket); - if (nVersion == 1 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) { + int nUBucketPos = + info.GetBucketPosition(nKey, true, bucket); + if (nVersion == 1 && + nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && + vvNew[bucket][nUBucketPos] == -1 && + info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) { info.nRefCount++; vvNew[bucket][nUBucketPos] = nIndex; } @@ -408,7 +460,8 @@ class CAddrMan // Prune new entries with refcount 0 (as a result of collisions). int nLostUnk = 0; - for (std::map::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) { + for (std::map::const_iterator it = mapInfo.begin(); + it != mapInfo.end();) { if (it->second.fInTried == false && it->second.nRefCount == 0) { std::map::const_iterator itCopy = it++; Delete(itCopy->first); @@ -418,19 +471,15 @@ class CAddrMan } } if (nLost + nLostUnk > 0) { - LogPrint("addrman", "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost); + LogPrint("addrman", "addrman lost %i new and %i tried addresses " + "due to collisions\n", + nLostUnk, nLost); } Check(); } - unsigned int GetSerializeSize(int nType, int nVersion) const - { - return (CSizeComputer(nType, nVersion) << *this).size(); - } - - void Clear() - { + void Clear() { std::vector().swap(vRandom); nKey = GetRandHash(); for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) { @@ -447,95 +496,85 @@ class CAddrMan nIdCount = 0; nTried = 0; nNew = 0; + // Initially at 1 so that "never" is strictly worse. + nLastGood = 1; } - CAddrMan() - { - Clear(); - } + CAddrMan() { Clear(); } - ~CAddrMan() - { - nKey.SetNull(); - } + ~CAddrMan() { nKey.SetNull(); } //! Return the number of (unique) addresses in all tables. - size_t size() const - { + size_t size() const { + // TODO: Cache this in an atomic to avoid this overhead + LOCK(cs); return vRandom.size(); } //! Consistency check - void Check() - { + void Check() { #ifdef DEBUG_ADDRMAN { LOCK(cs); int err; - if ((err=Check_())) + if ((err = Check_())) LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err); } #endif } //! Add a single address. - bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0) - { + bool Add(const CAddress &addr, const CNetAddr &source, + int64_t nTimePenalty = 0) { + LOCK(cs); bool fRet = false; - { - LOCK(cs); - Check(); - fRet |= Add_(addr, source, nTimePenalty); - Check(); - } + Check(); + fRet |= Add_(addr, source, nTimePenalty); + Check(); if (fRet) - LogPrint("addrman", "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew); + LogPrint("addrman", "Added %s from %s: %i tried, %i new\n", + addr.ToStringIPPort(), source.ToString(), nTried, nNew); return fRet; } //! Add multiple addresses. - bool Add(const std::vector &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0) - { + bool Add(const std::vector &vAddr, const CNetAddr &source, + int64_t nTimePenalty = 0) { + LOCK(cs); int nAdd = 0; - { - LOCK(cs); - Check(); - for (std::vector::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) - nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0; - Check(); - } + Check(); + for (std::vector::const_iterator it = vAddr.begin(); + it != vAddr.end(); it++) + nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0; + Check(); if (nAdd) - LogPrint("addrman", "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew); + LogPrint("addrman", + "Added %i addresses from %s: %i tried, %i new\n", nAdd, + source.ToString(), nTried, nNew); return nAdd > 0; } //! Mark an entry as accessible. - void Good(const CService &addr, int64_t nTime = GetAdjustedTime()) - { - { - LOCK(cs); - Check(); - Good_(addr, nTime); - Check(); - } + void Good(const CService &addr, int64_t nTime = GetAdjustedTime()) { + LOCK(cs); + Check(); + Good_(addr, nTime); + Check(); } //! Mark an entry as connection attempted to. - void Attempt(const CService &addr, int64_t nTime = GetAdjustedTime()) - { - { - LOCK(cs); - Check(); - Attempt_(addr, nTime); - Check(); - } + void Attempt(const CService &addr, bool fCountFailure, + int64_t nTime = GetAdjustedTime()) { + LOCK(cs); + Check(); + Attempt_(addr, fCountFailure, nTime); + Check(); } /** * Choose an address to connect to. */ - CAddrInfo Select(bool newOnly = false) - { + CAddrInfo Select(bool newOnly = false) { CAddrInfo addrRet; { LOCK(cs); @@ -547,8 +586,7 @@ class CAddrMan } //! Return a bunch of addresses, selected at random. - std::vector GetAddr() - { + std::vector GetAddr() { Check(); std::vector vAddr; { @@ -560,21 +598,19 @@ class CAddrMan } //! Mark an entry as currently-connected-to. - void Connected(const CService &addr, int64_t nTime = GetAdjustedTime()) - { - { - LOCK(cs); - Check(); - Connected_(addr, nTime); - Check(); - } - } - - //! Ensure that bucket placement is always the same for testing purposes. - void MakeDeterministic(){ - nKey.SetNull(); //Do not use outside of tests. + void Connected(const CService &addr, int64_t nTime = GetAdjustedTime()) { + LOCK(cs); + Check(); + Connected_(addr, nTime); + Check(); } + void SetServices(const CService &addr, ServiceFlags nServices) { + LOCK(cs); + Check(); + SetServices_(addr, nServices); + Check(); + } }; #endif // BITCOIN_ADDRMAN_H diff --git a/src/amount.h b/src/amount.h index d1ca768e..bec6b3c8 100644 --- a/src/amount.h +++ b/src/amount.h @@ -57,7 +57,7 @@ class CFeeRate ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nSatoshisPerK); } }; diff --git a/src/ans/ans.cpp b/src/ans/ans.cpp new file mode 100644 index 00000000..a03cc715 --- /dev/null +++ b/src/ans/ans.cpp @@ -0,0 +1,111 @@ +// Copyright (c) 2018 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "ans.h" + +#include + +bool CAnsZone::addRecord(AnsRecordTypes recordType, std::string key, CAnsRecord value) +{ + switch(recordType) + { + case Arec: + A.insert(std::make_pair(key, value)); + break; + case CNAMErec: + CNAME.insert(std::make_pair(key, value)); + break; + case PTRrec: + PTR.insert(std::make_pair(key, value)); + break; + default: + return false; + } + return true; +} + +CAnsRecord CAnsZone::getRecord(AnsRecordTypes recordType, std::string key) +{ + switch(recordType) + { + case Arec: + { + auto Aresult = A.find(key); + if(Aresult != A.end()) + { + return Aresult->second; + } + break; + } + case CNAMErec: + { + auto CNAMEresult = CNAME.find(key); + if(CNAMEresult != CNAME.end()) + { + return CNAMEresult->second; + } + break; + } + case PTRrec: + { + auto PTRresult = PTR.find(key); + if(PTRresult != PTR.end()) + { + return PTRresult->second; + } + break; + } + default: + break; + } + return CAnsRecord(); +} + +uint64_t CAnsZone::getRecordSetSize(AnsRecordTypes recordType) +{ + // we use a declared uint64_t here and return that instead of returning + // .size() because .size() is of type size_t + uint64_t recordSetSize; + switch(recordType) + { + case Arec: + { + recordSetSize = A.size(); + break; + } + case CNAMErec: + { + recordSetSize = CNAME.size(); + break; + } + case PTRrec: + { + recordSetSize = PTR.size(); + break; + } + default: + return 0; + } + return recordSetSize; +} + +void CAnsZone::clearRecordSet(AnsRecordTypes recordType) +{ + switch(recordType) + { + case Arec: + A.clear(); + break; + case CNAMErec: + CNAME.clear(); + break; + case PTRrec: + PTR.clear(); + break; + default: + break; + } +} + + diff --git a/src/ans/ans.h b/src/ans/ans.h new file mode 100644 index 00000000..3d5d1d79 --- /dev/null +++ b/src/ans/ans.h @@ -0,0 +1,28 @@ +// Copyright (c) 2018 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef ANS_H +#define ANS_H + +#include "ansrecord.h" + +#include +#include + +typedef std::unordered_map recordSet; + +class CAnsZone +{ +private: + recordSet A; + recordSet CNAME; + recordSet PTR; +public: + bool addRecord(AnsRecordTypes recordType, std::string key, CAnsRecord value); + CAnsRecord getRecord(AnsRecordTypes recordType, std::string key); + uint64_t getRecordSetSize(AnsRecordTypes recordType); + void clearRecordSet(AnsRecordTypes recordType); +}; + +#endif // ANS_H diff --git a/src/ans/ansrecord.cpp b/src/ans/ansrecord.cpp new file mode 100644 index 00000000..7a86c82a --- /dev/null +++ b/src/ans/ansrecord.cpp @@ -0,0 +1,45 @@ +// Copyright (c) 2018 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "ansrecord.h" + +void CAnsRecord::setValue(std::string strValue) +{ + value = strValue; +} + +std::string CAnsRecord::getValue() +{ + return value; +} + +void CAnsRecord::setExpireTime(uint64_t ntime) +{ + expireTime = ntime; +} + +uint64_t CAnsRecord::getExpireTime() +{ + return expireTime; +} + +void CAnsRecord::setPaymentHash(uint256 hash) +{ + paymentHash = hash; +} + +uint256 CAnsRecord::getPaymentHash() +{ + return paymentHash; +} + +void CAnsRecord::setServiceHash(uint256 hash) +{ + serviceHash = hash; +} + +uint256 CAnsRecord::getServiceHash() +{ + return serviceHash; +} diff --git a/src/ans/ansrecord.h b/src/ans/ansrecord.h new file mode 100644 index 00000000..2c200cad --- /dev/null +++ b/src/ans/ansrecord.h @@ -0,0 +1,38 @@ +// Copyright (c) 2018 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef ANSRECORD_H +#define ANSRECORD_H + +#include +#include "uint256.h" + +enum AnsRecordTypes{ + Arec, // name to address + CNAMErec, // name to name + PTRrec, // address to name +}; + +class CAnsRecord +{ +private: + std::string value; + uint64_t expireTime; + uint256 paymentHash; + uint256 serviceHash; +public: + void setValue(std::string strValue); + std::string getValue(); + + void setExpireTime(uint64_t ntime); + uint64_t getExpireTime(); + + void setPaymentHash(uint256 hash); + uint256 getPaymentHash(); + + void setServiceHash(uint256 hash); + uint256 getServiceHash(); +}; + +#endif // ANSRECORD_H diff --git a/src/args.cpp b/src/args.cpp index 1ef6023c..68a470e0 100644 --- a/src/args.cpp +++ b/src/args.cpp @@ -3,18 +3,14 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #include "args.h" -#include "util.h" +#include "util/util.h" -#include "chainparamsbase.h" +#include "networks/netman.h" #include "random.h" #include "serialize.h" -#include "utilstrencodings.h" -#include "utiltime.h" +#include "util/utilstrencodings.h" +#include "util/utiltime.h" #include @@ -84,10 +80,10 @@ #include #include -ArgsManager gArgs; +CArgsManager gArgs; /** Interpret string as boolean, for argument parsing */ -static bool InterpretBool(const std::string& strValue) +bool InterpretBool(const std::string& strValue) { if (strValue.empty()) return true; @@ -95,7 +91,7 @@ static bool InterpretBool(const std::string& strValue) } /** Turn -noX into -X=0 */ -static void InterpretNegativeSetting(std::string& strKey, std::string& strValue) +void InterpretNegativeSetting(std::string& strKey, std::string& strValue) { if (strKey.length()>3 && strKey[0]=='-' && strKey[1]=='n' && strKey[2]=='o') { @@ -104,7 +100,7 @@ static void InterpretNegativeSetting(std::string& strKey, std::string& strValue) } } -void ArgsManager::ParseParameters(int argc, const char* const argv[]) +void CArgsManager::ParseParameters(int argc, const char* const argv[]) { LOCK(cs_args); mapArgs.clear(); @@ -140,7 +136,7 @@ void ArgsManager::ParseParameters(int argc, const char* const argv[]) } } -std::vector ArgsManager::GetArgs(const std::string& strArg) +std::vector CArgsManager::GetArgs(const std::string& strArg) { LOCK(cs_args); if (IsArgSet(strArg)) @@ -148,13 +144,13 @@ std::vector ArgsManager::GetArgs(const std::string& strArg) return {}; } -bool ArgsManager::IsArgSet(const std::string& strArg) +bool CArgsManager::IsArgSet(const std::string& strArg) { LOCK(cs_args); return mapArgs.count(strArg); } -std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) +std::string CArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) { LOCK(cs_args); if (mapArgs.count(strArg)) @@ -162,7 +158,7 @@ std::string ArgsManager::GetArg(const std::string& strArg, const std::string& st return strDefault; } -int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault) +int64_t CArgsManager::GetArg(const std::string& strArg, int64_t nDefault) { LOCK(cs_args); if (mapArgs.count(strArg)) @@ -170,7 +166,7 @@ int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault) return nDefault; } -bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) +bool CArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) { LOCK(cs_args); if (mapArgs.count(strArg)) @@ -178,7 +174,7 @@ bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) return fDefault; } -bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue) +bool CArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue) { LOCK(cs_args); if (mapArgs.count(strArg)) @@ -187,7 +183,7 @@ bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strVa return true; } -bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue) +bool CArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue) { if (fValue) return SoftSetArg(strArg, std::string("1")); @@ -195,7 +191,7 @@ bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue) return SoftSetArg(strArg, std::string("0")); } -void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue) +void CArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue) { LOCK(cs_args); mapArgs[strArg] = strValue; @@ -207,7 +203,7 @@ static fs::path pathCached; static fs::path pathCachedNetSpecific; static CCriticalSection csPathCached; -boost::filesystem::path ArgsManager::GetConfigFile() +boost::filesystem::path CArgsManager::GetConfigFile() { boost::filesystem::path pathConfigFile(GetArg("-conf", CONF_FILENAME)); if (!pathConfigFile.is_complete()) @@ -216,7 +212,7 @@ boost::filesystem::path ArgsManager::GetConfigFile() return pathConfigFile; } -void ArgsManager::ReadConfigFile() +void CArgsManager::ReadConfigFile() { init: boost::filesystem::ifstream streamConfig(GetConfigFile()); diff --git a/src/args.h b/src/args.h index c3c29a4e..79b879c5 100644 --- a/src/args.h +++ b/src/args.h @@ -1,19 +1,11 @@ -// -// Created by parallels on 8/14/17. -// - #ifndef ECCOIN_ARGS_H #define ECCOIN_ARGS_H -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #include "compat.h" #include "fs.h" #include "sync.h" #include "tinyformat.h" -#include "utiltime.h" +#include "util/utiltime.h" #include #include @@ -24,7 +16,7 @@ #include -class ArgsManager +class CArgsManager { protected: CCriticalSection cs_args; @@ -94,7 +86,9 @@ class ArgsManager void ForceSetArg(const std::string& strArg, const std::string& strValue); }; -extern ArgsManager gArgs; +extern CArgsManager gArgs; +void InterpretNegativeSetting(std::string& strKey, std::string& strValue); +bool InterpretBool(const std::string& strValue); #endif //ECCOIN_ARGS_H diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index 2e613635..68e3c356 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -6,7 +6,7 @@ #include "arith_uint256.h" #include "uint256.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include "crypto/common.h" #include diff --git a/src/base58.cpp b/src/base58.cpp index 5e26cf8d..ef089cc7 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -4,8 +4,9 @@ #include "base58.h" -#include "hash.h" +#include "crypto/hash.h" #include "uint256.h" +#include "init.h" #include #include @@ -220,13 +221,13 @@ class CBitcoinAddressVisitor : public boost::static_visitor bool CBitcoinAddress::Set(const CKeyID& id) { - SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20); + SetData(pnetMan->getActivePaymentNetwork()->Base58Prefix(CNetworkTemplate::PUBKEY_ADDRESS), &id, 20); return true; } bool CBitcoinAddress::Set(const CScriptID& id) { - SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20); + SetData(pnetMan->getActivePaymentNetwork()->Base58Prefix(CNetworkTemplate::SCRIPT_ADDRESS), &id, 20); return true; } @@ -237,14 +238,14 @@ bool CBitcoinAddress::Set(const CTxDestination& dest) bool CBitcoinAddress::IsValid() const { - return IsValid(Params()); + return IsValid(pnetMan->getActivePaymentNetwork()); } -bool CBitcoinAddress::IsValid(const CChainParams& params) const +bool CBitcoinAddress::IsValid(const CNetworkTemplate ¶ms) const { bool fCorrectSize = vchData.size() == 20; - bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) || - vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); + bool fKnownVersion = vchVersion == params.Base58Prefix(CNetworkTemplate::PUBKEY_ADDRESS) || + vchVersion == params.Base58Prefix(CNetworkTemplate::SCRIPT_ADDRESS); return fCorrectSize && fKnownVersion; } @@ -254,9 +255,9 @@ CTxDestination CBitcoinAddress::Get() const return CNoDestination(); uint160 id; memcpy(&id, &vchData[0], 20); - if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) + if (vchVersion == pnetMan->getActivePaymentNetwork()->Base58Prefix(CNetworkTemplate::PUBKEY_ADDRESS)) return CKeyID(id); - else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) + else if (vchVersion == pnetMan->getActivePaymentNetwork()->Base58Prefix(CNetworkTemplate::SCRIPT_ADDRESS)) return CScriptID(id); else return CNoDestination(); @@ -264,7 +265,7 @@ CTxDestination CBitcoinAddress::Get() const bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const { - if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) + if (!IsValid() || vchVersion != pnetMan->getActivePaymentNetwork()->Base58Prefix(CNetworkTemplate::PUBKEY_ADDRESS)) return false; uint160 id; memcpy(&id, &vchData[0], 20); @@ -274,13 +275,13 @@ bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const bool CBitcoinAddress::IsScript() const { - return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); + return IsValid() && vchVersion == pnetMan->getActivePaymentNetwork()->Base58Prefix(CNetworkTemplate::SCRIPT_ADDRESS); } void CBitcoinSecret::SetKey(const CKey& vchSecret) { assert(vchSecret.IsValid()); - SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size()); + SetData(pnetMan->getActivePaymentNetwork()->Base58Prefix(CNetworkTemplate::SECRET_KEY), vchSecret.begin(), vchSecret.size()); if (vchSecret.IsCompressed()) vchData.push_back(1); } @@ -296,7 +297,7 @@ CKey CBitcoinSecret::GetKey() bool CBitcoinSecret::IsValid() const { bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1); - bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY); + bool fCorrectVersion = vchVersion == pnetMan->getActivePaymentNetwork()->Base58Prefix(CNetworkTemplate::SECRET_KEY); return fExpectedFormat && fCorrectVersion; } diff --git a/src/base58.h b/src/base58.h index a3980118..e12979b2 100644 --- a/src/base58.h +++ b/src/base58.h @@ -14,7 +14,9 @@ #ifndef BITCOIN_BASE58_H #define BITCOIN_BASE58_H -#include "chainparams.h" +#include "networks/networktemplate.h" +#include "networks/netman.h" +#include "init.h" #include "key.h" #include "pubkey.h" #include "script/script.h" @@ -107,7 +109,7 @@ class CBitcoinAddress : public CBase58Data { bool Set(const CScriptID &id); bool Set(const CTxDestination &dest); bool IsValid() const; - bool IsValid(const CChainParams ¶ms) const; + bool IsValid(const CNetworkTemplate ¶ms) const; CBitcoinAddress() {} CBitcoinAddress(const CTxDestination &dest) { Set(dest); } @@ -135,13 +137,13 @@ class CBitcoinSecret : public CBase58Data CBitcoinSecret() {} }; -template class CBitcoinExtKeyBase : public CBase58Data +template class CBitcoinExtKeyBase : public CBase58Data { public: void SetKey(const K &key) { unsigned char vch[Size]; key.Encode(vch); - SetData(Params().Base58Prefix(Type), vch, vch+Size); + SetData(pnetMan->getActivePaymentNetwork()->Base58Prefix(Type), vch, vch+Size); } K GetKey() { @@ -158,13 +160,13 @@ template class CBitcoinExtK } CBitcoinExtKeyBase(const std::string& strBase58c) { - SetString(strBase58c.c_str(), Params().Base58Prefix(Type).size()); + SetString(strBase58c.c_str(), pnetMan->getActivePaymentNetwork()->Base58Prefix(Type).size()); } CBitcoinExtKeyBase() {} }; -typedef CBitcoinExtKeyBase CBitcoinExtKey; -typedef CBitcoinExtKeyBase CBitcoinExtPubKey; +typedef CBitcoinExtKeyBase CBitcoinExtKey; +typedef CBitcoinExtKeyBase CBitcoinExtPubKey; #endif // BITCOIN_BASE58_H diff --git a/src/bloom.cpp b/src/bloom.cpp index 78659912..7f704279 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -4,8 +4,8 @@ #include "bloom.h" -#include "primitives/transaction.h" -#include "hash.h" +#include "tx/tx.h" +#include "crypto/hash.h" #include "script/script.h" #include "script/standard.h" #include "random.h" diff --git a/src/bloom.h b/src/bloom.h index d45635e7..c8a4ba9d 100644 --- a/src/bloom.h +++ b/src/bloom.h @@ -73,7 +73,7 @@ class CBloomFilter ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(vData); READWRITE(nHashFuncs); READWRITE(nTweak); diff --git a/src/build/chain/.gitignore b/src/build/chain/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/src/build/chain/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/src/build/networks/.gitignore b/src/build/networks/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/src/build/networks/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/src/build/rpc/.gitignore b/src/build/rpc/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/src/build/rpc/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/src/build/tx/.gitignore b/src/build/tx/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/src/build/tx/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/src/build/util/.gitignore b/src/build/util/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/src/build/util/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/src/primitives/block.cpp b/src/chain/block.cpp similarity index 94% rename from src/primitives/block.cpp rename to src/chain/block.cpp index ccd1c031..eeb1a45b 100644 --- a/src/primitives/block.cpp +++ b/src/chain/block.cpp @@ -3,18 +3,18 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "primitives/block.h" - -#include "hash.h" +#include "crypto/hash.h" #include "tinyformat.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include "crypto/common.h" #include "main.h" -#include "util.h" -#include "chain.h" +#include "util/util.h" +#include "chain/chain.h" #include "timedata.h" #include "crypto/scrypt.h" -#include "chainparams.h" +#include "networks/networktemplate.h" +#include "networks/netman.h" +#include "init.h" uint256 CBlockHeader::GetHash() const { @@ -123,7 +123,7 @@ bool CBlock::SignScryptBlock(const CKeyStore& keystore) bool CBlock::CheckBlockSignature() const { - if (GetHash() == Params().GetConsensus().hashGenesisBlock) + if (GetHash() == pnetMan->getActivePaymentNetwork()->GetConsensus().hashGenesisBlock) return vchBlockSig.empty(); std::vector > vSolutions; diff --git a/src/primitives/block.h b/src/chain/block.h similarity index 92% rename from src/primitives/block.h rename to src/chain/block.h index e0366704..e7f956bf 100644 --- a/src/primitives/block.h +++ b/src/chain/block.h @@ -6,7 +6,7 @@ #ifndef BITCOIN_PRIMITIVES_BLOCK_H #define BITCOIN_PRIMITIVES_BLOCK_H -#include "primitives/transaction.h" +#include "tx/tx.h" #include "serialize.h" #include "uint256.h" #include "keystore.h" @@ -38,7 +38,7 @@ class CBlockHeader ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(hashPrevBlock); @@ -107,7 +107,7 @@ class CBlock : public CBlockHeader ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(*(CBlockHeader*)this); READWRITE(vtx); READWRITE(vchBlockSig); @@ -162,8 +162,9 @@ struct CBlockLocator ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); READWRITE(vHave); } diff --git a/src/blockindex.cpp b/src/chain/blockindex.cpp similarity index 100% rename from src/blockindex.cpp rename to src/chain/blockindex.cpp diff --git a/src/blockindex.h b/src/chain/blockindex.h similarity index 97% rename from src/blockindex.h rename to src/chain/blockindex.h index 969a3833..e1ad8ccb 100644 --- a/src/blockindex.h +++ b/src/chain/blockindex.h @@ -4,8 +4,8 @@ #include "serialize.h" #include "uint256.h" #include "arith_uint256.h" -#include "primitives/transaction.h" -#include "primitives/block.h" +#include "tx/tx.h" +#include "block.h" #include "tinyformat.h" #include @@ -18,7 +18,7 @@ struct CDiskBlockPos ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(VARINT(nFile)); READWRITE(VARINT(nPos)); } @@ -329,8 +329,9 @@ class CDiskBlockIndex : public CBlockIndex ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(VARINT(nVersion)); READWRITE(VARINT(nHeight)); diff --git a/src/chain.cpp b/src/chain/chain.cpp similarity index 99% rename from src/chain.cpp rename to src/chain/chain.cpp index 02808328..7ac3b5ec 100644 --- a/src/chain.cpp +++ b/src/chain/chain.cpp @@ -58,3 +58,5 @@ const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const { pindex = pindex->pprev; return pindex; } + + diff --git a/src/chain.h b/src/chain/chain.h similarity index 91% rename from src/chain.h rename to src/chain/chain.h index 6874fb17..8d580015 100644 --- a/src/chain.h +++ b/src/chain/chain.h @@ -7,7 +7,7 @@ #define BITCOIN_CHAIN_H #include "arith_uint256.h" -#include "primitives/block.h" +#include "block.h" #include "pow.h" #include "tinyformat.h" #include "uint256.h" @@ -21,6 +21,12 @@ class CChain { std::vector vChain; public: + + ~CChain() + { + vChain.clear(); + } + /** Returns the index entry for the genesis block of this chain, or NULL if none. */ CBlockIndex *Genesis() const { return vChain.size() > 0 ? vChain[0] : NULL; @@ -31,6 +37,12 @@ class CChain { return vChain.size() > 0 ? vChain[vChain.size() - 1] : NULL; } + CBlockIndex* AtHeight(int nHeight) const { + if (nHeight < 0 || nHeight >= (int)vChain.size()) + return NULL; + return vChain[nHeight]; + } + /** Returns the index entry at a particular height in this chain, or NULL if no such height exists. */ CBlockIndex *operator[](int nHeight) const { if (nHeight < 0 || nHeight >= (int)vChain.size()) diff --git a/src/chain/chainman.cpp b/src/chain/chainman.cpp new file mode 100644 index 00000000..f116e11c --- /dev/null +++ b/src/chain/chainman.cpp @@ -0,0 +1,408 @@ +// Copyright (c) 2017 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chainman.h" +#include "main.h" +#include "checkpoints.h" +#include "networks/netman.h" +#include "kernel.h" +#include "consensus/consensus.h" +#include "processblock.h" +#include "processheader.h" +#include +#include "txmempool.h" +#include "init.h" +#include "messages.h" +#include "undo.h" + +CBlockIndex* CChainManager::AddToBlockIndex(const CBlockHeader& block) +{ + // Check for duplicate + uint256 hash = block.GetHash(); + BlockMap::iterator it = mapBlockIndex.find(hash); + if (it != mapBlockIndex.end()) + return it->second; + + // Construct new block index object + CBlockIndex* pindexNew = new CBlockIndex(block); + assert(pindexNew); + // We assign the sequence id to blocks only when the full data is available, + // to avoid miners withholding blocks but broadcasting headers, to get a + // competitive advantage. + pindexNew->nSequenceId = 0; + BlockMap::iterator mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first; + pindexNew->phashBlock = &((*mi).first); + BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); + if (miPrev != mapBlockIndex.end()) + { + pindexNew->pprev = (*miPrev).second; + pindexNew->nHeight = pindexNew->pprev->nHeight + 1; + pindexNew->BuildSkip(); + } + pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); + pindexNew->RaiseValidity(BLOCK_VALID_TREE); + if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork) + pindexBestHeader = pindexNew; + + setDirtyBlockIndex.insert(pindexNew); + + return pindexNew; +} + +CBlockIndex* CChainManager::FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) +{ + // Find the first block the caller has in the main chain + for (auto const& hash: locator.vHave) { + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*mi).second; + if (chain.Contains(pindex)) + return pindex; + } + } + return chain.Genesis(); +} + +bool CChainManager::IsInitialBlockDownload() +{ + const CNetworkTemplate& chainParams = pnetMan->getActivePaymentNetwork(); + LOCK(cs_main); + if (fImporting || fReindex) + return true; + if (fCheckpointsEnabled && chainActive.Height() < Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints())) + return true; + static bool lockIBDState = false; + if (lockIBDState) + return false; + bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || + pindexBestHeader->GetBlockTime() < GetTime() - chainParams.MaxTipAge()); + if (!state) + lockIBDState = true; + return state; +} + +CBlockIndex* CChainManager::InsertBlockIndex(uint256 hash) +{ + if (hash.IsNull()) + return NULL; + + // Return existing + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + return (*mi).second; + + // Create new + CBlockIndex* pindexNew = new CBlockIndex(); + mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first; + pindexNew->phashBlock = &((*mi).first); + + return pindexNew; +} + +bool CChainManager::InitBlockIndex(const CNetworkTemplate& chainparams) +{ + LOCK(cs_main); + + // Initialize global variables that cannot be constructed at startup. + recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); + + // Check whether we're already initialized + if (chainActive.Genesis() != NULL) + return true; + + // Use the provided setting for -txindex in the new database + pblocktree->WriteFlag("txindex", true); + LogPrintf("Initializing databases...\n"); + + // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) + if (!fReindex) { + try { + CBlock &block = const_cast(chainparams.GenesisBlock()); + // Start new block file + unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); + CDiskBlockPos blockPos; + CValidationState state; + if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime())) + return error("InitBlockIndex(): FindBlockPos failed"); + if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) + return error("InitBlockIndex(): writing genesis block to disk failed"); + CBlockIndex *pindex = AddToBlockIndex(block); + + // ppcoin: compute stake entropy bit for stake modifier + if (!pindex->SetStakeEntropyBit(block.GetStakeEntropyBit())) + { + return error("InitBlockIndex() : SetStakeEntropyBit() failed"); + } + // ppcoin: compute stake modifier + uint256 nStakeModifier; + nStakeModifier.SetNull(); + CTransaction nullTx; + if (!ComputeNextStakeModifier(pindex->pprev, nullTx, nStakeModifier)) + return error("InitBlockIndex() : ComputeNextStakeModifier() failed"); + pindex->SetStakeModifier(nStakeModifier); + if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) + return error("InitBlockIndex(): genesis block not accepted"); + if (!ActivateBestChain(state, chainparams, LOADED, &block)) + return error("InitBlockIndex(): genesis block cannot be activated"); + // Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data + return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); + } catch (const std::runtime_error& e) { + return error("InitBlockIndex(): failed to initialize block database: %s", e.what()); + } + } + + return true; +} + +bool CChainManager::LoadBlockIndex() +{ + // Load block index from databases + if (!fReindex && !LoadBlockIndexDB()) + return false; + return true; +} + +bool CChainManager::LoadBlockIndexDB() +{ + int64_t nStart = GetTimeMillis(); + if (!pblocktree->LoadBlockIndexGuts()) + return false; + LogPrintf("LoadBlockIndexGuts %15dms\n", GetTimeMillis() - nStart); + nStart = GetTimeMillis(); + + + boost::this_thread::interruption_point(); + + // Calculate nChainWork + std::vector > vSortedByHeight; + vSortedByHeight.reserve(mapBlockIndex.size()); + for (const std::pair& item : mapBlockIndex) + { + CBlockIndex* pindex = item.second; + vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex)); + } + LogPrintf("Sort block index %15dms\n", GetTimeMillis() - nStart); + nStart = GetTimeMillis(); + std::sort(vSortedByHeight.begin(), vSortedByHeight.end()); + for (const std::pair& item : vSortedByHeight) + { + CBlockIndex* pindex = item.second; + pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex); + // We can link the chain of blocks for which we've received transactions at some point. + // Pruned nodes may have deleted the block. + if (pindex->nTx > 0) { + if (pindex->pprev) { + if (pindex->pprev->nChainTx) { + pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx; + } else { + pindex->nChainTx = 0; + mapBlocksUnlinked.insert(std::make_pair(pindex->pprev, pindex)); + } + } else { + pindex->nChainTx = pindex->nTx; + } + } + if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL)) + setBlockIndexCandidates.insert(pindex); + if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork)) + pindexBestInvalid = pindex; + if (pindex->pprev) + pindex->BuildSkip(); + if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == NULL || CBlockIndexWorkComparator()(pindexBestHeader, pindex))) + pindexBestHeader = pindex; + } + LogPrintf("calc nChainWork, nChainTx, valid, statns, pprev %15dms\n", GetTimeMillis() - nStart); + nStart = GetTimeMillis(); + + // Load block file info + pblocktree->ReadLastBlockFile(nLastBlockFile); + vinfoBlockFile.resize(nLastBlockFile + 1); + LogPrintf("%s: last block file = %i\n", __func__, nLastBlockFile); + for (int nFile = 0; nFile <= nLastBlockFile; nFile++) { + pblocktree->ReadBlockFileInfo(nFile, vinfoBlockFile[nFile]); + } + LogPrintf("%s: last block file info: %s\n", __func__, vinfoBlockFile[nLastBlockFile].ToString()); + for (int nFile = nLastBlockFile + 1; true; nFile++) { + CBlockFileInfo info; + if (pblocktree->ReadBlockFileInfo(nFile, info)) { + vinfoBlockFile.push_back(info); + } else { + break; + } + } + + // Check presence of blk files + LogPrintf("Checking all blk files are present...\n"); + std::set setBlkDataFiles; + for (auto const& item: mapBlockIndex) + { + CBlockIndex* pindex = item.second; + if (pindex->nStatus & BLOCK_HAVE_DATA) { + setBlkDataFiles.insert(pindex->nFile); + } + } + for (std::set::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) + { + CDiskBlockPos pos(*it, 0); + if (CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION).IsNull()) { + return false; + } + } + LogPrintf("block file checks %15dms\n", GetTimeMillis() - nStart); + nStart = GetTimeMillis(); + + // Check whether we need to continue reindexing + bool fReindexing = false; + pblocktree->ReadReindexing(fReindexing); + if(fReindexing) fReindex = true; + LogPrintf("reindexing check %15dms\n", GetTimeMillis() - nStart); + nStart = GetTimeMillis(); + + // Load pointer to end of best chain + BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); + if (it == mapBlockIndex.end()) + return true; + chainActive.SetTip(it->second); + + PruneBlockIndexCandidates(); + + return true; +} + + +bool CChainManager::LoadExternalBlockFile(const CNetworkTemplate& chainparams, FILE* fileIn, CDiskBlockPos *dbp) +{ + // std::map of disk positions for blocks with unknown parent (only used for reindex) + static std::multimap mapBlocksUnknownParent; + int64_t nStart = GetTimeMillis(); + + int nLoaded = 0; + try { + // This takes over fileIn and calls fclose() on it in the CBufferedFile destructor + CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); + uint64_t nRewind = blkdat.GetPos(); + while (!blkdat.eof()) { + boost::this_thread::interruption_point(); + + blkdat.SetPos(nRewind); + nRewind++; // start one byte further next time, in case of failure + blkdat.SetLimit(); // remove former limit + unsigned int nSize = 0; + try { + // locate a header + unsigned char buf[MESSAGE_START_SIZE]; + blkdat.FindByte(chainparams.MessageStart()[0]); + nRewind = blkdat.GetPos()+1; + blkdat >> FLATDATA(buf); + if (memcmp(buf, chainparams.MessageStart(), MESSAGE_START_SIZE)) + continue; + // read size + blkdat >> nSize; + if (nSize < 80 || nSize > MAX_BLOCK_SIZE) + continue; + } catch (const std::exception&) { + // no valid block header found; don't complain + break; + } + try { + // read block + uint64_t nBlockPos = blkdat.GetPos(); + if (dbp) + dbp->nPos = nBlockPos; + blkdat.SetLimit(nBlockPos + nSize); + blkdat.SetPos(nBlockPos); + CBlock block; + blkdat >> block; + nRewind = blkdat.GetPos(); + + // detect out of order blocks, and store them for later + uint256 hash = block.GetHash(); + if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { + LogPrint("reindex", "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), + block.hashPrevBlock.ToString()); + if (dbp) + mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp)); + continue; + } + + // process in case the block isn't known yet + if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { + CValidationState state; + if (ProcessNewBlock(state, chainparams, NULL, &block, true, dbp, LOADED)) + nLoaded++; + if (state.IsError()) + break; + } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { + LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); + } + + // Recursively process earlier encountered successors of this block + std::deque queue; + queue.push_back(hash); + while (!queue.empty()) { + uint256 head = queue.front(); + queue.pop_front(); + std::pair::iterator, std::multimap::iterator> range = mapBlocksUnknownParent.equal_range(head); + while (range.first != range.second) { + std::multimap::iterator it = range.first; + if (ReadBlockFromDisk(block, it->second, chainparams.GetConsensus())) + { + LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), + head.ToString()); + CValidationState dummy; + if (ProcessNewBlock(dummy, chainparams, NULL, &block, true, &it->second, LOADED)) + { + nLoaded++; + queue.push_back(block.GetHash()); + } + } + range.first++; + mapBlocksUnknownParent.erase(it); + } + } + } catch (const std::exception& e) { + LogPrintf("%s: Deserialize or I/O error - %s\n", __func__, e.what()); + } + } + } catch (const std::runtime_error& e) { + AbortNode(std::string("System error: ") + e.what()); + } + if (nLoaded > 0) + LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, GetTimeMillis() - nStart); + return nLoaded > 0; +} + +void CChainManager::UnloadBlockIndex() +{ + LOCK(cs_main); + setBlockIndexCandidates.clear(); + chainActive.SetTip(NULL); + pindexBestInvalid = NULL; + pindexBestHeader = NULL; + mempool.clear(); + mapOrphanTransactions.clear(); + mapOrphanTransactionsByPrev.clear(); + nSyncStarted = 0; + mapBlocksUnlinked.clear(); + vinfoBlockFile.clear(); + nLastBlockFile = 0; + nBlockSequenceId = 1; + mapBlockSource.clear(); + mapBlocksInFlight.clear(); + nPreferredDownload = 0; + setDirtyBlockIndex.clear(); + setDirtyFileInfo.clear(); + mapNodeState.clear(); + recentRejects.reset(NULL); + versionbitscache.Clear(); + for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) { + warningcache[b].clear(); + } + + for (auto& entry: mapBlockIndex) { + delete entry.second; + } + mapBlockIndex.clear(); +} diff --git a/src/chain/chainman.h b/src/chain/chainman.h new file mode 100644 index 00000000..887289ac --- /dev/null +++ b/src/chain/chainman.h @@ -0,0 +1,104 @@ +// Copyright (c) 2017 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef CHAINMAN_H +#define CHAINMAN_H + +#include + +#include "networks/networktemplate.h" +#include "chain.h" +#include "txdb.h" + + +struct BlockHasher +{ + size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); } +}; +typedef boost::unordered_map BlockMap; + + +/** Manages the BlockMap and CChain's for a given protocol. */ +class CChainManager { + +public: + /** map containing all block indexs ever seen for this chain */ + BlockMap mapBlockIndex; + + /** The currently-connected chain of blocks (protected by cs_main). */ + CChain chainActive; + + /** Best header we've seen so far (used for getheaders queries' starting points). */ + CBlockIndex *pindexBestHeader; + + /** Global variable that points to the active CCoinsView (protected by cs_main) */ + std::unique_ptr pcoinsTip; + + /** Global variable that points to the active block tree (protected by cs_main) */ + CBlockTreeDB *pblocktree; + +private: + bool LoadBlockIndexDB(); + +public: + + CChainManager(){ + mapBlockIndex.clear(); + chainActive = CChain(); + pindexBestHeader = NULL; + pcoinsTip.reset(); + pblocktree = NULL; + } + + ~CChainManager() + { + // block headers + BlockMap::iterator it1 = mapBlockIndex.begin(); + for (; it1 != mapBlockIndex.end(); it1++) + delete (*it1).second; + mapBlockIndex.clear(); + delete pindexBestHeader; + pcoinsTip.reset(); + delete pblocktree; + } + + void operator=(const CChainManager& oldMan) + { + mapBlockIndex = oldMan.mapBlockIndex; + chainActive = oldMan.chainActive; + pindexBestHeader = oldMan.pindexBestHeader; + pcoinsTip.reset(oldMan.pcoinsTip.get()); + pblocktree = oldMan.pblocktree; + } + + + /** Add a new block index entry for a given block recieved from the network */ + CBlockIndex* AddToBlockIndex(const CBlockHeader& block); + + /** Find the last common block between the parameter chain and a locator. */ + CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator); + + /** Check whether we are doing an initial block download (synchronizing from disk or network) */ + bool IsInitialBlockDownload(); + + /** Initialize a new block tree database + block data on disk */ + bool InitBlockIndex(const CNetworkTemplate& chainparams); + + /** Create a new block index entry for a given block hash loaded from disk*/ + CBlockIndex* InsertBlockIndex(uint256 hash); + + /** Load the block tree and coins database from disk */ + bool LoadBlockIndex(); + + /** Import blocks from an external file */ + bool LoadExternalBlockFile(const CNetworkTemplate& chainparams, FILE* fileIn, CDiskBlockPos *dbp = NULL); + + /** Unload database information */ + void UnloadBlockIndex(); + + + +}; + +#endif // CHAINMAN_H diff --git a/src/checkpoints.cpp b/src/chain/checkpoints.cpp similarity index 91% rename from src/checkpoints.cpp rename to src/chain/checkpoints.cpp index 7c4471b7..6427a5c5 100644 --- a/src/checkpoints.cpp +++ b/src/chain/checkpoints.cpp @@ -5,9 +5,10 @@ #include "checkpoints.h" #include "chain.h" -#include "chainparams.h" +#include "networks/networktemplate.h" #include "main.h" #include "uint256.h" +#include "init.h" #include #include @@ -72,8 +73,8 @@ namespace Checkpoints { BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints) { const uint256& hash = i.second; - BlockMap::const_iterator t = mapBlockIndex.find(hash); - if (t != mapBlockIndex.end()) + BlockMap::const_iterator t = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(hash); + if (t != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) return t->second; } return NULL; diff --git a/src/checkpoints.h b/src/chain/checkpoints.h similarity index 100% rename from src/checkpoints.h rename to src/chain/checkpoints.h diff --git a/src/chainparams.cpp b/src/chainparams.cpp deleted file mode 100644 index c3ce18a7..00000000 --- a/src/chainparams.cpp +++ /dev/null @@ -1,187 +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 "chainparams.h" -#include "consensus/merkle.h" - -#include "tinyformat.h" -#include "util.h" -#include "args.h" -#include "utilstrencodings.h" - -#include - -#include - -/** - * Main network - */ -/** - * What makes a good checkpoint block? - * + Is surrounded by blocks with reasonable timestamps - * (no blocks before with a timestamp after, none after with - * timestamp before) - * + Contains no strange transactions - */ - -class CMainParams : public CChainParams { -public: - CMainParams() { - strNetworkID = "main"; - consensus.nSubsidyHalvingInterval = 210000; - consensus.nMajorityEnforceBlockUpgrade = 750; - consensus.nMajorityRejectBlockOutdated = 950; - consensus.nMajorityWindow = 1000; - consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - consensus.posLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - consensus.nTargetTimespan = 30 * 45; - consensus.nTargetSpacing = 45; - consensus.fPowAllowMinDifficultyBlocks = false; - consensus.fPowNoRetargeting = false; - consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 - consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nTargetSpacing - 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 - - // Deployment of BIP68, BIP112, and BIP113. - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1462060800; // May 1st, 2016 - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017 - - /** - * The message start string is designed to be unlikely to occur in normal data. - * The characters are rarely used upper ASCII, not valid as UTF-8, and produce - * a large 32-bit integer with any alignment. - */ - pchMessageStart[0] = 0xce; - pchMessageStart[1] = 0xf1; - pchMessageStart[2] = 0xdb; - pchMessageStart[3] = 0xfa; - vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"); - nDefaultPort = 19118; - nMaxTipAge = 24 * 60 * 60; - nStakeMaxAge = 60*60*24*84; //84 days - nStakeMinAge = 60*60*2; // 2 hours - - const char* pszTimestamp = "AP | Mar 2, 2014, 10.35 AM IST: China blames Uighur separatists for knife attack; 33 dead"; - CTransaction txNew; - txNew.nTime = 1393744287; - txNew.vin.resize(1); - txNew.vout.resize(1); - txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(9999) << std::vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); - txNew.vout[0].SetEmpty(); - txNew.vout[0].SetEmpty(); - - genesis.vtx.push_back(txNew); - genesis.hashPrevBlock.SetNull(); - genesis.nVersion = 1; - genesis.nTime = 1393744307; - genesis.nBits = 0x1e0fffff; - genesis.nNonce = 12799721; - genesis.hashMerkleRoot = BlockMerkleRoot(genesis); - - consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("0xa60ac43c88dbc44b826cf315352a8a7b373d2af8b6e1c4c4a0638859c5e9ecd1")); - assert(genesis.hashMerkleRoot == uint256S("0x4db82fe8b45f3dae2b7c7b8be5ec4c37e72e25eaf989b9db24ce1d0fd37eed8b")); - - vSeeds.push_back(CDNSSeedData("CryptoUnitedSeed", "www.cryptounited.io")); - vSeeds.push_back(CDNSSeedData("ECC-Seed1", "138.197.100.45")); - vSeeds.push_back(CDNSSeedData("ECC-Seed2", "159.203.172.212")); - vSeeds.push_back(CDNSSeedData("ECC-Seed3", "eccnode.altj.com")); - - base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,33); - base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,8); - base58Prefixes[SECRET_KEY] = std::vector(1,161); - base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container >(); - base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container >(); - - fMiningRequiresPeers = true; - fDefaultConsistencyChecks = false; - fRequireStandard = true; - fMineBlocksOnDemand = false; - fTestnetToBeDeprecatedFieldRPC = false; - - checkpointData = (CCheckpointData){ - boost::assign::map_list_of - ( 0, uint256S("0xa60ac43c88dbc44b826cf315352a8a7b373d2af8b6e1c4c4a0638859c5e9ecd1")) - ( 1, uint256S("0x00000762d19a3a38458e73de6c937fd483f17bd75f55d7fe4e95713f51d6b816")) - ( 2, uint256S("0x00000ea50ea0cae64779ff4bb4a0ee94841e2ee20642641a062cbdd342e0a3c5")) - ( 3, uint256S("0x00000513cc6f4bec8d7e7bd0ded854200b6c784c8c830a3e4fd0cccc2cb9e58c")) - ( 1000, uint256S("0x000000000df3f7a5f719c247782d7a43d75186ebc043341e2668320f9d940bcd")) - ( 10000, uint256S("0x00000000076d45a9579c879d46354dd81eeba7060a9a065e13c9dd1c28f474d1")) - ( 23920, uint256S("0x000000000331540c766c4ac667a6fbc65ff93f5a30fbb0c6822986885b1b56c0")) - ( 36918, uint256S("0x0000000001353725582b099cdd3c89933bbd08a17ace464fba935ecfc41572ef")) - ( 50000, uint256S("0x0000000001c770384cd12a74eb5456358425fc6a94a250c3466aaa2ca7460131")) - ( 86401, uint256S("0x51bb1ac3ffd009c12791b9d4320dec0ba69e15c8b6d03d17889b0c09fb5b05a4")) - ( 86402, uint256S("0xa9f3141e571231e02b4fb649370af6173e1a80a9e0d21aa8859bd17ce1260a05")) - ( 86403, uint256S("0xf6c11aadca44fce2390107e229d4d0d70f7cf64266b959672711c68e0f411af5")) - ( 86759, uint256S("0x5c6ed2e23ccc27d59a0659a9a32a4c0ca97d829249277c6a35918f4ec94b1748")) - ( 86761, uint256S("0xca305a45c9f8a89c050f004d0438b38f190fe6bfe51128f0c3e864ddcf2c765c")) - ( 86901, uint256S("0xe769d38b7e140267b688f9d9cc6b58d38185427facb6a1aa719db60a0d54f3f7")) - ( 87000, uint256S("0xbb069ba59aa5a6acc68413ef7c2d0c009b061daf160edf958738d197a059f11d")) - ( 87101, uint256S("0x1ffbfd2a70e626d5f848775851e6f89bee6f2225ed78131b16f9547449d2e2ee")) - ( 96500, uint256S("0x13f0755045a3ae90d33c4bcf6ba1581025fc6e0caf46f7624063cb59dcc3d27c")) - (100000, uint256S("0x28a483386650a188c3346fd5e329e2c8cc137cf3557547e8525f5cdea601501a")) - (136500, uint256S("0x7e4ec82a165762e8a324038ef1cdd0b83e603f4737ae6f9e5967b13b8b6ace5c")) - (150000, uint256S("0xfee6d00910e8d0aa2f0ca8a447b4de366a12f9df2521f77c5a97a5ae0af8834e")) - (185000, uint256S("0xce904504a0df58944c6a633b739abcec3bbb256b510a616b465c24525d564828")) - (197712, uint256S("0x7576d0f370b1efdce01075a9491fb8d2f98af485f78d170196270f1eb156ee40")) - (200000, uint256S("0x1f1ea51aee8a7456655e31857c7cd4a9f494556438485abd4c60d86cacf24b44")) - (205000, uint256S("0x9e4528bc818bb1ee2cdf44ba7805e88b4fc85bbf496516f35d4d642c6812503e")) - (209762, uint256S("0x49448f382f9ec8f126542244573e7349c7b07db0cbdc2ab8326942cbfff603b3")) - (209786, uint256S("0x28558eedf7f5c049e9f2ea61da270fffc5b50310aafb29c7595840784e8b1d61")) - (215650, uint256S("0xd7fb37df6be4bf2c5c9ea47ba4a14f9af35c326cd225122b03f61b74d1283d09")) - (215690, uint256S("0x8af4d5450c238460a4775b19c94872eaf5664657f702bef53576bc9f77af319d")) - (220504, uint256S("0x5781d160a46a6631a21e62a9a67932d0f9b8636c8f5241973b076db3854de405")) - (221000, uint256S("0x51cd22cde58a3738e851f155a282b4624d3e18e84fbcb02de5006029dec8f7e3")) - (233855, uint256S("0x77c1312f0b4ba0fc34cb7a0f3472012739bbd22c317add69edaa4908e83b00eb")) - (236850, uint256S("0x139203f72c943433880c4f8d3581a4cb7ee0877f341639cd4c7810edc7fc7d80")) - (237000, uint256S("0x70fdb4f39e571afff137c7bd40c4df98ccab32cec1d305074bac9fca30754bc0")) - (241130, uint256S("0xdd900777cb9e2ea2cae0bf410ce2f2484a415c7bf7af59d9492868195583e3b2")) - (242150, uint256S("0xba96de8da95ac53cedc7fd0cd3c17b32f5d3a04f33a544060606c095b28bf4c1")) - (300000, uint256S("0x2c654dfa9f1ab51a64509910b1f053fc20d572022480814988c36f042cb3010b")) - (350000, uint256S("0xfdb1df53f4365d494d9fa54247a533cbfcd9b6992491f40c8ccfeed454932a70")) - (400000, uint256S("0xc04d360938d5ff66294100a10424f7e284abe76d117f28460e16752edeb03444")) - (435000, uint256S("0x801a211aa479129e42554bc812d624e585e1b0dd608e23b1a7f87a9d14e7fdec")) - (450000, uint256S("0x53e21a2574ff6acc0f31640c4058554dde2fe8972ec72867403e8b88e9ba1bc6")) - (500000, uint256S("0x779f22407cf9fa0adb8a361918ccf249ef913070ce368070c1ac5063005e3e3c")) - (550000, uint256S("0xf340b738c21c0a9b6b2eff0f40d9ab3fca9830d8597131680cd5a2615594cfb0")) - (600000, uint256S("0x589fc3d25c15caaa468dc8b4249e1cbb6ea18368897bd3b1d80f1404486e3783")) - (650000, uint256S("0xc28634f7211ff0582dfe8df1849711a9bd7815005e59dff0059a20876c465f51")) - (675000, uint256S("0xe1aca23bd72ad9d153767272f43d33a0542d2a61a78e281341d0f12cd0521024")) - (675500, uint256S("0x26ccdf8bcb1a50ecef8f507de74ff030789aa1b52491fc4a4de4e4679d53a398")) - (687345, uint256S("0xae2e43c35a3346fa798a0a356ca7a4bce57885ee64e4319295f7f3b7210944f1")) - (700000, uint256S("0x0ab361e8acd391c6b5e726eb4704dd8d60e2e3b3f8856e2f7d6373c9a3e0da36")) - (702950, uint256S("0x26d2cd7b13f1aaa34ffc379696d0e5b14c2ddf8ef2c2c78348fec23f8b55e8ff")) - (1030250,uint256S("0x434ee5c39b6ba186d66cbfaaa8004910b3556726f990b9f33bb48b9fc280c5de")) - (1491250,uint256S("0x45a01a2b45ca91433c8c12378914463bd13afc410b27eeb18855d5b060d7e270")) - (1492500,uint256S("0xd4185d9ae0c38211ac6e0ceddcca4207a00fc59d11b087e76c9bf6d4081856c8")) - (1493040,uint256S("0xcd266ca5eaca1f561d3adf5ab0bc4994ea26418dd12d9072d5c5194639c40ac2")) - }; - } -}; -static CMainParams mainParams; - -static CChainParams *pCurrentParams = 0; - -const CChainParams &Params() { - assert(pCurrentParams); - return *pCurrentParams; -} - -CChainParams& Params(const std::string& chain) -{ - if (chain == CBaseChainParams::MAIN) - return mainParams; - else - throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); -} - -void SelectParams(const std::string& network) -{ - SelectBaseParams(network); - pCurrentParams = &Params(network); -} diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp deleted file mode 100644 index 04c98328..00000000 --- a/src/chainparamsbase.cpp +++ /dev/null @@ -1,111 +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 "chainparamsbase.h" - -#include "tinyformat.h" -#include "util.h" -#include "args.h" - -#include - -const std::string CBaseChainParams::MAIN = "main"; -const std::string CBaseChainParams::TESTNET = "test"; -const std::string CBaseChainParams::REGTEST = "regtest"; - -void AppendParamsHelpMessages(std::string& strUsage, bool debugHelp) -{ - strUsage += HelpMessageGroup(_("Chain selection options:")); - strUsage += HelpMessageOpt("-testnet", _("Use the test chain")); - if (debugHelp) { - strUsage += HelpMessageOpt("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. " - "This is intended for regression testing tools and app development."); - } -} - -/** - * Main network - */ -class CBaseMainParams : public CBaseChainParams -{ -public: - CBaseMainParams() - { - nRPCPort = 8332; - } -}; -static CBaseMainParams mainParams; - -/** - * Testnet (v3) - */ -class CBaseTestNetParams : public CBaseChainParams -{ -public: - CBaseTestNetParams() - { - nRPCPort = 18332; - strDataDir = "testnet3"; - } -}; -static CBaseTestNetParams testNetParams; - -/* - * Regression test - */ -class CBaseRegTestParams : public CBaseChainParams -{ -public: - CBaseRegTestParams() - { - nRPCPort = 18332; - strDataDir = "regtest"; - } -}; -static CBaseRegTestParams regTestParams; - -static CBaseChainParams* pCurrentBaseParams = 0; - -const CBaseChainParams& BaseParams() -{ - assert(pCurrentBaseParams); - return *pCurrentBaseParams; -} - -CBaseChainParams& BaseParams(const std::string& chain) -{ - if (chain == CBaseChainParams::MAIN) - return mainParams; - else if (chain == CBaseChainParams::TESTNET) - return testNetParams; - else if (chain == CBaseChainParams::REGTEST) - return regTestParams; - else - throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); -} - -void SelectBaseParams(const std::string& chain) -{ - pCurrentBaseParams = &BaseParams(chain); -} - -std::string ChainNameFromCommandLine() -{ - bool fRegTest = gArgs.GetBoolArg("-regtest", false); - bool fTestNet = gArgs.GetBoolArg("-testnet", false); - - if (fTestNet && fRegTest) - throw std::runtime_error("Invalid combination of -regtest and -testnet."); - if (fRegTest) - return CBaseChainParams::REGTEST; - if (fTestNet) - return CBaseChainParams::TESTNET; - return CBaseChainParams::MAIN; -} - -bool AreBaseParamsConfigured() -{ - return pCurrentBaseParams != NULL; -} diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h deleted file mode 100644 index 59493afb..00000000 --- a/src/chainparamsbase.h +++ /dev/null @@ -1,62 +0,0 @@ -// 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. - -#ifndef BITCOIN_CHAINPARAMSBASE_H -#define BITCOIN_CHAINPARAMSBASE_H - -#include -#include - -/** - * CBaseChainParams defines the base parameters (shared between bitcoin-cli and bitcoind) - * of a given instance of the Bitcoin system. - */ -class CBaseChainParams -{ -public: - /** BIP70 chain name strings (main, test or regtest) */ - static const std::string MAIN; - static const std::string TESTNET; - static const std::string REGTEST; - - const std::string& DataDir() const { return strDataDir; } - int RPCPort() const { return nRPCPort; } - -protected: - CBaseChainParams() {} - - int nRPCPort; - std::string strDataDir; -}; - -/** - * Append the help messages for the chainparams options to the - * parameter string. - */ -void AppendParamsHelpMessages(std::string& strUsage, bool debugHelp=true); - -/** - * Return the currently selected parameters. This won't change after app - * startup, except for unit tests. - */ -const CBaseChainParams& BaseParams(); - -CBaseChainParams& BaseParams(const std::string& chain); - -/** Sets the params returned by Params() to those for the given network. */ -void SelectBaseParams(const std::string& chain); - -/** - * Looks for -regtest, -testnet and returns the appropriate BIP70 chain name. - * @return CBaseChainParams::MAX_NETWORK_TYPES if an invalid combination is given. CBaseChainParams::MAIN by default. - */ -std::string ChainNameFromCommandLine(); - -/** - * Return true if SelectBaseParamsFromCommandLine() has been called to select - * a network. - */ -bool AreBaseParamsConfigured(); - -#endif // BITCOIN_CHAINPARAMSBASE_H diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 11d62073..befb1d90 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -43,7 +43,6 @@ const std::string CLIENT_NAME("ECC"); #endif //! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. -#define GIT_ARCHIVE 1 #ifdef GIT_ARCHIVE #define GIT_COMMIT_ID "9779e1e1f32" #define GIT_COMMIT_DATE "Mon, 11 Apr 2016 13:01:43 +0200" diff --git a/src/clientversion.h b/src/clientversion.h index fe9c3753..6d1382c2 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -5,10 +5,6 @@ #ifndef BITCOIN_CLIENTVERSION_H #define BITCOIN_CLIENTVERSION_H -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#else - /** * client versioning and copyright year */ @@ -17,7 +13,7 @@ #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 2 #define CLIENT_VERSION_REVISION 5 -#define CLIENT_VERSION_BUILD 5 +#define CLIENT_VERSION_BUILD 6 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true @@ -28,8 +24,6 @@ */ #define COPYRIGHT_YEAR 2017 -#endif //HAVE_CONFIG_H - /** * Converts the parameter X to a string after macro replacement on X has been performed. * Don't merge these into one macro! @@ -57,6 +51,8 @@ static const int CLIENT_VERSION = + 100 * CLIENT_VERSION_REVISION + 1 * CLIENT_VERSION_BUILD; +static const int WALLET_VERSION = 60000; + extern const std::string CLIENT_NAME; extern const std::string CLIENT_BUILD; extern const std::string CLIENT_DATE; diff --git a/src/coincontrol.h b/src/coincontrol.h index 9626ad2c..5f261794 100644 --- a/src/coincontrol.h +++ b/src/coincontrol.h @@ -5,7 +5,7 @@ #ifndef BITCOIN_COINCONTROL_H #define BITCOIN_COINCONTROL_H -#include "primitives/transaction.h" +#include "tx/tx.h" /** Coin Control Features. */ class CCoinControl diff --git a/src/coins.cpp b/src/coins.cpp index 5599d98b..051719ee 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -6,7 +6,7 @@ #include "memusage.h" #include "random.h" -#include "util.h" +#include "util/util.h" #include /** @@ -44,6 +44,7 @@ bool CCoins::Spend(uint32_t nPos) bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; } bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; } uint256 CCoinsView::GetBestBlock() const { return uint256(); } +std::vector CCoinsView::GetHeadBlocks() const { return std::vector(); } bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; } bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; } @@ -52,6 +53,7 @@ CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { } bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); } bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); } uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); } +std::vector CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); } diff --git a/src/coins.h b/src/coins.h index 61980c9b..689654c6 100644 --- a/src/coins.h +++ b/src/coins.h @@ -17,6 +17,58 @@ #include +/** + * A UTXO entry. + * + * Serialized format: + * - VARINT((coinbase ? 1 : 0) | (height << 1)) + * - the non-spent CTxOut (via CTxOutCompressor) + */ +class Coin { + //! Unspent transaction output. + CTxOut out; + + //! Whether containing transaction was a coinbase and height at which the + //! transaction was included into a block. + uint32_t nHeightAndIsCoinBase; + +public: + //! Empty constructor + Coin() : nHeightAndIsCoinBase(0) {} + + //! Constructor from a CTxOut and height/coinbase information. + Coin(CTxOut outIn, uint32_t nHeightIn, bool IsCoinbase) + : out(std::move(outIn)), + nHeightAndIsCoinBase((nHeightIn << 1) | IsCoinbase) {} + + uint32_t GetHeight() const { return nHeightAndIsCoinBase >> 1; } + bool IsCoinBase() const { return nHeightAndIsCoinBase & 0x01; } + bool IsSpent() const { return out.IsNull(); } + + CTxOut &GetTxOut() { return out; } + const CTxOut &GetTxOut() const { return out; } + + void Clear() { + out.SetNull(); + nHeightAndIsCoinBase = 0; + } + + template void Serialize(Stream &s) const { + assert(!IsSpent()); + ::Serialize(s, VARINT(nHeightAndIsCoinBase)); + ::Serialize(s, CTxOutCompressor(REF(out))); + } + + template void Unserialize(Stream &s) { + ::Unserialize(s, VARINT(nHeightAndIsCoinBase)); + ::Unserialize(s, REF(CTxOutCompressor(out))); + } + + size_t DynamicMemoryUsage() const { + return memusage::DynamicUsage(out.scriptPubKey); + } +}; + /** * Pruned version of CTransaction: only retains metadata and unspent transaction outputs * @@ -175,7 +227,7 @@ class CCoins } template - void Serialize(Stream &s, int nType, int nVersion) const { + void Serialize(Stream &s) const { unsigned int nMaskSize = 0, nMaskCode = 0; CalcMaskSize(nMaskSize, nMaskCode); bool fFirst = vout.size() > 0 && !vout[0].IsNull(); @@ -183,33 +235,33 @@ class CCoins assert(fFirst || fSecond || nMaskCode); unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0); // version - ::Serialize(s, VARINT(this->nVersion), nType, nVersion); + ::Serialize(s, VARINT(this->nVersion)); // header code - ::Serialize(s, VARINT(nCode), nType, nVersion); + ::Serialize(s, VARINT(nCode)); // spentness bitmask for (unsigned int b = 0; b - void Unserialize(Stream &s, int nType, int nVersion) { + void Unserialize(Stream &s) { unsigned int nCode = 0; // version - ::Unserialize(s, VARINT(this->nVersion), nType, nVersion); + ::Unserialize(s, VARINT(this->nVersion)); // header code - ::Unserialize(s, VARINT(nCode), nType, nVersion); + ::Unserialize(s, VARINT(nCode)); fCoinBase = nCode & 1; std::vector vAvail(2, false); vAvail[0] = (nCode & 2) != 0; @@ -218,7 +270,7 @@ class CCoins // spentness bitmask while (nMaskCode > 0) { unsigned char chAvail = 0; - ::Unserialize(s, chAvail, nType, nVersion); + ::Unserialize(s, chAvail); for (unsigned int p = 0; p < 8; p++) { bool f = (chAvail & (1 << p)) != 0; vAvail.push_back(f); @@ -230,10 +282,10 @@ class CCoins vout.assign(vAvail.size(), CTxOut()); for (unsigned int i = 0; i < vAvail.size(); i++) { if (vAvail[i]) - ::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion); + ::Unserialize(s, REF(CTxOutCompressor(vout[i]))); } // coinbase height - ::Unserialize(s, VARINT(nHeight), nType, nVersion); + ::Unserialize(s, VARINT(nHeight)); Cleanup(); } @@ -324,6 +376,12 @@ class CCoinsView //! Retrieve the block hash whose state this CCoinsView currently represents virtual uint256 GetBestBlock() const; + //! Retrieve the range of blocks that may have been only partially written. + //! If the database is in a consistent state, the result is the empty vector. + //! Otherwise, a two-element vector is returned consisting of the new and + //! the old block hash, in that order. + virtual std::vector GetHeadBlocks() const; + //! Do a bulk modification (multiple CCoins changes + BestBlock change). //! The passed mapCoins can be modified. virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); @@ -347,6 +405,7 @@ class CCoinsViewBacked : public CCoinsView bool GetCoins(const uint256 &txid, CCoins &coins) const; bool HaveCoins(const uint256 &txid) const; uint256 GetBestBlock() const; + std::vector GetHeadBlocks() const override; void SetBackend(CCoinsView &viewIn); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); bool GetStats(CCoinsStats &stats) const; diff --git a/src/compat.h b/src/compat.h index a663fe3b..762d06ad 100644 --- a/src/compat.h +++ b/src/compat.h @@ -6,10 +6,6 @@ #ifndef BITCOIN_COMPAT_H #define BITCOIN_COMPAT_H -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #ifdef WIN32 #ifdef _WIN32_WINNT #undef _WIN32_WINNT diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h index 899220bd..f27cefea 100644 --- a/src/compat/byteswap.h +++ b/src/compat/byteswap.h @@ -5,10 +5,6 @@ #ifndef BITCOIN_COMPAT_BYTESWAP_H #define BITCOIN_COMPAT_BYTESWAP_H -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #include #if defined(HAVE_BYTESWAP_H) diff --git a/src/compat/crypto_endian.h b/src/compat/crypto_endian.h index 4d232ec1..1f852499 100644 --- a/src/compat/crypto_endian.h +++ b/src/compat/crypto_endian.h @@ -5,10 +5,6 @@ #ifndef BITCOIN_COMPAT_ENDIAN_H #define BITCOIN_COMPAT_ENDIAN_H -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #include #include "compat/byteswap.h" @@ -16,7 +12,30 @@ #ifdef __linux__ #include #elif __APPLE__ -#include +#include + +#include + +#define htobe16(x) OSSwapHostToBigInt16(x) +#define htole16(x) OSSwapHostToLittleInt16(x) +#define be16toh(x) OSSwapBigToHostInt16(x) +#define le16toh(x) OSSwapLittleToHostInt16(x) + +#define htobe32(x) OSSwapHostToBigInt32(x) +#define htole32(x) OSSwapHostToLittleInt32(x) +#define be32toh(x) OSSwapBigToHostInt32(x) +#define le32toh(x) OSSwapLittleToHostInt32(x) + +#define htobe64(x) OSSwapHostToBigInt64(x) +#define htole64(x) OSSwapHostToLittleInt64(x) +#define be64toh(x) OSSwapBigToHostInt64(x) +#define le64toh(x) OSSwapLittleToHostInt64(x) + +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + #else #if defined(WORDS_BIGENDIAN) diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp index b83dafdf..09695d45 100644 --- a/src/compat/glibc_compat.cpp +++ b/src/compat/glibc_compat.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #include #if defined(HAVE_SYS_SELECT_H) diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp index d62d74d4..deb2dd25 100644 --- a/src/compat/glibc_sanity.cpp +++ b/src/compat/glibc_sanity.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #include #if defined(HAVE_SYS_SELECT_H) diff --git a/src/compat/strnlen.cpp b/src/compat/strnlen.cpp index 1ac266c2..d96c79eb 100644 --- a/src/compat/strnlen.cpp +++ b/src/compat/strnlen.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #include #if HAVE_DECL_STRNLEN == 0 diff --git a/src/compressor.cpp b/src/compressor.cpp index 20c154fc..df508cf3 100644 --- a/src/compressor.cpp +++ b/src/compressor.cpp @@ -5,7 +5,7 @@ #include "compressor.h" -#include "hash.h" +#include "crypto/hash.h" #include "pubkey.h" #include "script/standard.h" diff --git a/src/compressor.h b/src/compressor.h index 84d3aa44..b48d1a95 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -6,66 +6,60 @@ #ifndef BITCOIN_COMPRESSOR_H #define BITCOIN_COMPRESSOR_H -#include "primitives/transaction.h" +#include "tx/tx.h" #include "script/script.h" #include "serialize.h" + class CKeyID; class CPubKey; class CScriptID; -/** Compact serializer for scripts. +/** + * Compact serializer for scripts. * - * It detects common cases and encodes them much more efficiently. - * 3 special cases are defined: + * It detects common cases and encodes them much more efficiently. + * 3 special cases are defined: * * Pay to pubkey hash (encoded as 21 bytes) * * Pay to script hash (encoded as 21 bytes) * * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes) * - * Other scripts up to 121 bytes require 1 byte + script length. Above - * that, scripts up to 16505 bytes require 2 bytes + script length. + * Other scripts up to 121 bytes require 1 byte + script length. Above that, + * scripts up to 16505 bytes require 2 bytes + script length. */ -class CScriptCompressor -{ +class CScriptCompressor { private: /** - * make this static for now (there are only 6 special scripts defined) - * this can potentially be extended together with a new nVersion for - * transactions, in which case this value becomes dependent on nVersion - * and nHeight of the enclosing transaction. + * make this static for now (there are only 6 special scripts defined) this + * can potentially be extended together with a new nVersion for + * transactions, in which case this value becomes dependent on nVersion and + * nHeight of the enclosing transaction. */ static const unsigned int nSpecialScripts = 6; CScript &script; + protected: /** - * These check for scripts for which a special case with a shorter encoding is defined. - * They are implemented separately from the CScript test, as these test for exact byte - * sequence correspondences, and are more strict. For example, IsToPubKey also verifies - * whether the public key is valid (as invalid ones cannot be represented in compressed - * form). + * These check for scripts for which a special case with a shorter encoding + * is defined. They are implemented separately from the CScript test, as + * these test for exact byte sequence correspondences, and are more strict. + * For example, IsToPubKey also verifies whether the public key is valid (as + * invalid ones cannot be represented in compressed form). */ bool IsToKeyID(CKeyID &hash) const; bool IsToScriptID(CScriptID &hash) const; bool IsToPubKey(CPubKey &pubkey) const; - bool Compress(std::vector &out) const; + bool Compress(std::vector &out) const; unsigned int GetSpecialSize(unsigned int nSize) const; - bool Decompress(unsigned int nSize, const std::vector &out); -public: - CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } + bool Decompress(unsigned int nSize, const std::vector &out); - unsigned int GetSerializeSize(int nType, int nVersion) const { - std::vector compr; - if (Compress(compr)) - return compr.size(); - unsigned int nSize = script.size() + nSpecialScripts; - return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion); - } +public: + CScriptCompressor(CScript &scriptIn) : script(scriptIn) {} - template - void Serialize(Stream &s, int nType, int nVersion) const { - std::vector compr; + template void Serialize(Stream &s) const { + std::vector compr; if (Compress(compr)) { s << CFlatData(compr); return; @@ -75,25 +69,29 @@ class CScriptCompressor s << CFlatData(script); } - template - void Unserialize(Stream &s, int nType, int nVersion) { + template void Unserialize(Stream &s) { unsigned int nSize = 0; s >> VARINT(nSize); if (nSize < nSpecialScripts) { - std::vector vch(GetSpecialSize(nSize), 0x00); + std::vector vch(GetSpecialSize(nSize), 0x00); s >> REF(CFlatData(vch)); Decompress(nSize, vch); return; } nSize -= nSpecialScripts; - script.resize(nSize); - s >> REF(CFlatData(script)); + if (nSize > MAX_SCRIPT_SIZE) { + // Overly long script, replace with a short invalid one + script << OP_RETURN; + s.ignore(nSize); + } else { + script.resize(nSize); + s >> REF(CFlatData(script)); + } } }; /** wrapper for CTxOut that provides a more compact serialization */ -class CTxOutCompressor -{ +class CTxOutCompressor { private: CTxOut &txout; @@ -101,12 +99,12 @@ class CTxOutCompressor static uint64_t CompressAmount(uint64_t nAmount); static uint64_t DecompressAmount(uint64_t nAmount); - CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { } + CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) {} - ADD_SERIALIZE_METHODS + ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream &s, Operation ser_action) { if (!ser_action.ForRead()) { uint64_t nVal = CompressAmount(txout.nValue); READWRITE(VARINT(nVal)); diff --git a/src/config/.gitignore b/src/config/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/src/config/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp index 9a8afa8a..11948410 100644 --- a/src/consensus/merkle.cpp +++ b/src/consensus/merkle.cpp @@ -1,6 +1,6 @@ #include "merkle.h" -#include "hash.h" -#include "utilstrencodings.h" +#include "crypto/hash.h" +#include "util/utilstrencodings.h" /* WARNING! If you're reading this because you're learning about crypto and/or designing a new system that will use merkle trees, keep in mind diff --git a/src/consensus/merkle.h b/src/consensus/merkle.h index 6ef59745..c8a2195c 100644 --- a/src/consensus/merkle.h +++ b/src/consensus/merkle.h @@ -8,8 +8,7 @@ #include #include -#include "primitives/transaction.h" -#include "primitives/block.h" +#include "chain/block.h" #include "uint256.h" uint256 ComputeMerkleRoot(const std::vector& leaves, bool* mutated = NULL); diff --git a/src/consensus/params.h b/src/consensus/params.h index dba021aa..fc20ab0b 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -15,7 +15,7 @@ namespace Consensus { enum DeploymentPos { DEPLOYMENT_TESTDUMMY, - DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113. + DEPLPUYMENT_CSV_PLACEHOLDER, // Deployment of BIP68, BIP112, and BIP113. MAX_VERSION_BITS_DEPLOYMENTS }; @@ -36,7 +36,6 @@ struct BIP9Deployment { */ struct Params { uint256 hashGenesisBlock; - int nSubsidyHalvingInterval; /** Used to check majorities for block version upgrade */ int nMajorityEnforceBlockUpgrade; int nMajorityRejectBlockOutdated; diff --git a/src/core_memusage.h b/src/core_memusage.h index 9157c74a..0da906f4 100644 --- a/src/core_memusage.h +++ b/src/core_memusage.h @@ -5,8 +5,8 @@ #ifndef BITCOIN_CORE_MEMUSAGE_H #define BITCOIN_CORE_MEMUSAGE_H -#include "primitives/transaction.h" -#include "primitives/block.h" +#include "tx/tx.h" +#include "chain/block.h" #include "memusage.h" static inline size_t RecursiveDynamicUsage(const CScript& script) { diff --git a/src/core_read.cpp b/src/core_read.cpp index 863361ed..2bcafe80 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -4,13 +4,13 @@ #include "core_io.h" -#include "primitives/block.h" -#include "primitives/transaction.h" +#include "chain/block.h" +#include "tx/tx.h" #include "script/script.h" #include "serialize.h" #include "streams.h" -#include "util.h" -#include "utilstrencodings.h" +#include "util/util.h" +#include "util/utilstrencodings.h" #include "version.h" #include diff --git a/src/core_write.cpp b/src/core_write.cpp index bd6e691a..8765838a 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -5,14 +5,14 @@ #include "core_io.h" #include "base58.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include "script/script.h" #include "script/standard.h" #include "serialize.h" #include "streams.h" -#include "util.h" -#include "utilmoneystr.h" -#include "utilstrencodings.h" +#include "util/util.h" +#include "util/utilmoneystr.h" +#include "util/utilstrencodings.h" #include diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp new file mode 100644 index 00000000..7c175c6e --- /dev/null +++ b/src/crypto/chacha20.cpp @@ -0,0 +1,190 @@ +// Copyright (c) 2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// Based on the public domain implementation 'merged' by D. J. Bernstein +// See https://cr.yp.to/chacha.html. + +#include "crypto/chacha20.h" +#include "crypto/common.h" + +#include + +constexpr static inline uint32_t rotl32(uint32_t v, int c) { + return (v << c) | (v >> (32 - c)); +} + +#define QUARTERROUND(a, b, c, d) \ + a += b; \ + d = rotl32(d ^ a, 16); \ + c += d; \ + b = rotl32(b ^ c, 12); \ + a += b; \ + d = rotl32(d ^ a, 8); \ + c += d; \ + b = rotl32(b ^ c, 7); + +static const uint8_t sigma[] = "expand 32-byte k"; +static const uint8_t tau[] = "expand 16-byte k"; + +void ChaCha20::SetKey(const uint8_t *k, size_t keylen) { + const uint8_t *constants; + + input[4] = ReadLE32(k + 0); + input[5] = ReadLE32(k + 4); + input[6] = ReadLE32(k + 8); + input[7] = ReadLE32(k + 12); + if (keylen == 32) { + // recommended + k += 16; + constants = sigma; + } else { + // keylen == 16 + constants = tau; + } + input[8] = ReadLE32(k + 0); + input[9] = ReadLE32(k + 4); + input[10] = ReadLE32(k + 8); + input[11] = ReadLE32(k + 12); + input[0] = ReadLE32(constants + 0); + input[1] = ReadLE32(constants + 4); + input[2] = ReadLE32(constants + 8); + input[3] = ReadLE32(constants + 12); + input[12] = 0; + input[13] = 0; + input[14] = 0; + input[15] = 0; +} + +ChaCha20::ChaCha20() { + memset(input, 0, sizeof(input)); +} + +ChaCha20::ChaCha20(const uint8_t *k, size_t keylen) { + SetKey(k, keylen); +} + +void ChaCha20::SetIV(uint64_t iv) { + input[14] = iv; + input[15] = iv >> 32; +} + +void ChaCha20::Seek(uint64_t pos) { + input[12] = pos; + input[13] = pos >> 32; +} + +void ChaCha20::Output(uint8_t *c, size_t bytes) { + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, + x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, + j15; + uint8_t *ctarget = nullptr; + uint8_t tmp[64]; + unsigned int i; + + if (!bytes) { + return; + } + + j0 = input[0]; + j1 = input[1]; + j2 = input[2]; + j3 = input[3]; + j4 = input[4]; + j5 = input[5]; + j6 = input[6]; + j7 = input[7]; + j8 = input[8]; + j9 = input[9]; + j10 = input[10]; + j11 = input[11]; + j12 = input[12]; + j13 = input[13]; + j14 = input[14]; + j15 = input[15]; + + for (;;) { + if (bytes < 64) { + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20; i > 0; i -= 2) { + QUARTERROUND(x0, x4, x8, x12) + QUARTERROUND(x1, x5, x9, x13) + QUARTERROUND(x2, x6, x10, x14) + QUARTERROUND(x3, x7, x11, x15) + QUARTERROUND(x0, x5, x10, x15) + QUARTERROUND(x1, x6, x11, x12) + QUARTERROUND(x2, x7, x8, x13) + QUARTERROUND(x3, x4, x9, x14) + } + x0 += j0; + x1 += j1; + x2 += j2; + x3 += j3; + x4 += j4; + x5 += j5; + x6 += j6; + x7 += j7; + x8 += j8; + x9 += j9; + x10 += j10; + x11 += j11; + x12 += j12; + x13 += j13; + x14 += j14; + x15 += j15; + + ++j12; + if (!j12) { + ++j13; + } + + WriteLE32(c + 0, x0); + WriteLE32(c + 4, x1); + WriteLE32(c + 8, x2); + WriteLE32(c + 12, x3); + WriteLE32(c + 16, x4); + WriteLE32(c + 20, x5); + WriteLE32(c + 24, x6); + WriteLE32(c + 28, x7); + WriteLE32(c + 32, x8); + WriteLE32(c + 36, x9); + WriteLE32(c + 40, x10); + WriteLE32(c + 44, x11); + WriteLE32(c + 48, x12); + WriteLE32(c + 52, x13); + WriteLE32(c + 56, x14); + WriteLE32(c + 60, x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0; i < bytes; ++i) { + ctarget[i] = c[i]; + } + } + input[12] = j12; + input[13] = j13; + return; + } + bytes -= 64; + c += 64; + } +} diff --git a/src/crypto/chacha20.h b/src/crypto/chacha20.h new file mode 100644 index 00000000..9c0f1102 --- /dev/null +++ b/src/crypto/chacha20.h @@ -0,0 +1,25 @@ +// Copyright (c) 2017 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_CRYPTO_CHACHA20_H +#define BITCOIN_CRYPTO_CHACHA20_H + +#include +#include + +/** A PRNG class for ChaCha20. */ +class ChaCha20 { +private: + uint32_t input[16]; + +public: + ChaCha20(); + ChaCha20(const uint8_t *key, size_t keylen); + void SetKey(const uint8_t *key, size_t keylen); + void SetIV(uint64_t iv); + void Seek(uint64_t pos); + void Output(uint8_t *output, size_t bytes); +}; + +#endif // BITCOIN_CRYPTO_CHACHA20_H diff --git a/src/crypto/common.h b/src/crypto/common.h index beaf7d89..7e19cf31 100644 --- a/src/crypto/common.h +++ b/src/crypto/common.h @@ -5,10 +5,6 @@ #ifndef BITCOIN_CRYPTO_COMMON_H #define BITCOIN_CRYPTO_COMMON_H -#if defined(HAVE_CONFIG_H) -#include "bitcoin-config.h" -#endif - #include #include "compat/crypto_endian.h" diff --git a/src/hash.cpp b/src/crypto/hash.cpp similarity index 92% rename from src/hash.cpp rename to src/crypto/hash.cpp index 0e0cc6e4..c837cebd 100644 --- a/src/hash.cpp +++ b/src/crypto/hash.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "hash.h" +#include "crypto/hash.h" #include "crypto/common.h" #include "crypto/hmac_sha512.h" #include "pubkey.h" @@ -79,6 +79,6 @@ void BIP32Hash(const unsigned char chainCode[32], unsigned int nChild, unsigned num[1] = (nChild >> 16) & 0xFF; num[2] = (nChild >> 8) & 0xFF; num[3] = (nChild >> 0) & 0xFF; - CHMAC_SHA512(chainCode[0], 32).Write(&header, 1).Write(data, 32).Write(num, 4).Finalize(output); + CHMAC_SHA512(reinterpret_cast(chainCode[0]), 32).Write(&header, 1).Write(data, 32).Write(num, 4).Finalize(output); } diff --git a/src/hash.h b/src/crypto/hash.h similarity index 99% rename from src/hash.h rename to src/crypto/hash.h index 05d90d65..88f701be 100644 --- a/src/hash.h +++ b/src/crypto/hash.h @@ -153,7 +153,7 @@ class CHashWriter template CHashWriter& operator<<(const T& obj) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } }; diff --git a/src/crypto/scrypt.h b/src/crypto/scrypt.h index c58e3045..d1d73e30 100644 --- a/src/crypto/scrypt.h +++ b/src/crypto/scrypt.h @@ -5,7 +5,7 @@ #include #include "net.h" -#include "primitives/block.h" +#include "chain/block.h" void *scrypt_buffer_alloc(); void scrypt_buffer_free(void *scratchpad); diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index ff808906..979042c7 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -4,7 +4,7 @@ #include "dbwrapper.h" -#include "util.h" +#include "util/util.h" #include "random.h" #include @@ -84,10 +84,10 @@ CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, b Write(OBFUSCATE_KEY_KEY, new_key); obfuscate_key = new_key; - LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), GetObfuscateKeyHex()); + LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string().c_str(), HexStr(obfuscate_key).c_str()); } - LogPrintf("Using obfuscation key for %s: %s\n", path.string(), GetObfuscateKeyHex()); + LogPrintf("Using obfuscation key for %s: %s\n", path.string().c_str(), HexStr(obfuscate_key).c_str()); } CDBWrapper::~CDBWrapper() @@ -102,7 +102,7 @@ CDBWrapper::~CDBWrapper() options.env = NULL; } -bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) throw(dbwrapper_error) +bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) { leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch); HandleError(status); @@ -136,17 +136,34 @@ bool CDBWrapper::IsEmpty() return !(it->Valid()); } -const std::vector& CDBWrapper::GetObfuscateKey() const -{ - return obfuscate_key; -} - -std::string CDBWrapper::GetObfuscateKeyHex() const -{ - return HexStr(obfuscate_key); -} CDBIterator::~CDBIterator() { delete piter; } bool CDBIterator::Valid() { return piter->Valid(); } void CDBIterator::SeekToFirst() { piter->SeekToFirst(); } void CDBIterator::Next() { piter->Next(); } + +namespace dbwrapper_private +{ + void HandleError(const leveldb::Status &status) + { + if (status.ok()) { + return; + } + LogPrintf("%s\n", status.ToString()); + if (status.IsCorruption()) { + throw dbwrapper_error("Database corrupted"); + } + if (status.IsIOError()) { + throw dbwrapper_error("Database I/O error"); + } + if (status.IsNotFound()) { + throw dbwrapper_error("Database entry missing"); + } + throw dbwrapper_error("Unknown database error"); + } + + const std::vector &GetObfuscateKey(const CDBWrapper &w) + { + return w.obfuscate_key; + } +} diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 5e7313f7..535863dd 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -8,8 +8,8 @@ #include "clientversion.h" #include "serialize.h" #include "streams.h" -#include "util.h" -#include "utilstrencodings.h" +#include "util/util.h" +#include "util/utilstrencodings.h" #include "version.h" #include @@ -17,126 +17,169 @@ #include #include -class dbwrapper_error : public std::runtime_error -{ + +static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64; +static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024; + +class dbwrapper_error : public std::runtime_error { public: - dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {} + dbwrapper_error(const std::string &msg) : std::runtime_error(msg) {} }; -void HandleError(const leveldb::Status& status) throw(dbwrapper_error); +class CDBWrapper; + +/** + * These should be considered an implementation detail of the specific database. + */ +namespace dbwrapper_private { + +/** + * Handle database error by throwing dbwrapper_error exception. + */ +void HandleError(const leveldb::Status &status); + +/** + * Work around circular dependency, as well as for testing in dbwrapper_tests. + * Database obfuscation should be considered an implementation detail of the + * specific database. + */ +const std::vector &GetObfuscateKey(const CDBWrapper &w); +}; /** Batch of changes queued to be written to a CDBWrapper */ -class CDBBatch -{ +class CDBBatch { friend class CDBWrapper; private: + const CDBWrapper &parent; leveldb::WriteBatch batch; - const std::vector *obfuscate_key; + + CDataStream ssKey; + CDataStream ssValue; + + size_t size_estimate; public: /** - * @param[in] obfuscate_key If passed, XOR data with this key. + * @param[in] _parent CDBWrapper that this batch is to be submitted to */ - CDBBatch(const std::vector *obfuscate_key) : obfuscate_key(obfuscate_key) { }; + CDBBatch(const CDBWrapper &_parent) + : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), + ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0){}; - template - void Write(const K& key, const V& value) - { - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(ssKey.GetSerializeSize(key)); + void Clear() { + batch.Clear(); + size_estimate = 0; + } + + template void Write(const K &key, const V &value) { + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; - leveldb::Slice slKey(&ssKey[0], ssKey.size()); + leveldb::Slice slKey(ssKey.data(), ssKey.size()); - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - ssValue.reserve(ssValue.GetSerializeSize(value)); + ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE); ssValue << value; - ssValue.Xor(*obfuscate_key); - leveldb::Slice slValue(&ssValue[0], ssValue.size()); + ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent)); + leveldb::Slice slValue(ssValue.data(), ssValue.size()); batch.Put(slKey, slValue); + // LevelDB serializes writes as: + // - byte: header + // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...) + // - byte[]: key + // - varint: value length + // - byte[]: value + // The formula below assumes the key and value are both less than 16k. + size_estimate += 3 + (slKey.size() > 127) + slKey.size() + + (slValue.size() > 127) + slValue.size(); + ssKey.clear(); + ssValue.clear(); } - template - void Erase(const K& key) - { - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(ssKey.GetSerializeSize(key)); + template void Erase(const K &key) { + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; - leveldb::Slice slKey(&ssKey[0], ssKey.size()); + leveldb::Slice slKey(ssKey.data(), ssKey.size()); batch.Delete(slKey); + // LevelDB serializes erases as: + // - byte: header + // - varint: key length + // - byte[]: key + // The formula below assumes the key is less than 16kB. + size_estimate += 2 + (slKey.size() > 127) + slKey.size(); + ssKey.clear(); } + + size_t SizeEstimate() const { return size_estimate; } }; -class CDBIterator -{ +class CDBIterator { private: + const CDBWrapper &parent; leveldb::Iterator *piter; - const std::vector *obfuscate_key; public: - /** - * @param[in] piterIn The original leveldb iterator. - * @param[in] obfuscate_key If passed, XOR data with this key. + * @param[in] _parent Parent CDBWrapper instance. + * @param[in] _piter The original leveldb iterator. */ - CDBIterator(leveldb::Iterator *piterIn, const std::vector* obfuscate_key) : - piter(piterIn), obfuscate_key(obfuscate_key) { }; + CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) + : parent(_parent), piter(_piter){}; ~CDBIterator(); bool Valid(); void SeekToFirst(); - template void Seek(const K& key) { + template void Seek(const K &key) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(ssKey.GetSerializeSize(key)); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; - leveldb::Slice slKey(&ssKey[0], ssKey.size()); + leveldb::Slice slKey(ssKey.data(), ssKey.size()); piter->Seek(slKey); } void Next(); - template bool GetKey(K& key) { + template bool GetKey(K &key) { leveldb::Slice slKey = piter->key(); try { - CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); + CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), + SER_DISK, CLIENT_VERSION); ssKey >> key; - } catch (const std::exception&) { + } catch (const std::exception &) { return false; } return true; } - unsigned int GetKeySize() { - return piter->key().size(); - } + unsigned int GetKeySize() { return piter->key().size(); } - template bool GetValue(V& value) { + template bool GetValue(V &value) { leveldb::Slice slValue = piter->value(); try { - CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); - ssValue.Xor(*obfuscate_key); + CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), + SER_DISK, CLIENT_VERSION); + ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent)); ssValue >> value; - } catch (const std::exception&) { + } catch (const std::exception &) { return false; } return true; } - unsigned int GetValueSize() { - return piter->value().size(); - } - + unsigned int GetValueSize() { return piter->value().size(); } }; -class CDBWrapper -{ +class CDBWrapper { + friend const std::vector & + dbwrapper_private::GetObfuscateKey(const CDBWrapper &w); + private: - //! custom environment this database is using (may be NULL in case of default environment) - leveldb::Env* penv; + //! custom environment this database is using (may be nullptr in case of + //! default environment) + leveldb::Env *penv; //! database options used leveldb::Options options; @@ -154,10 +197,10 @@ class CDBWrapper leveldb::WriteOptions syncoptions; //! the database itself - leveldb::DB* pdb; + leveldb::DB *pdb; //! a key used for optional XOR-obfuscation of the database - std::vector obfuscate_key; + std::vector obfuscate_key; //! the key under which the obfuscation key is stored static const std::string OBFUSCATE_KEY_KEY; @@ -165,98 +208,90 @@ class CDBWrapper //! the length of the obfuscate key in number of bytes static const unsigned int OBFUSCATE_KEY_NUM_BYTES; - std::vector CreateObfuscateKey() const; + std::vector CreateObfuscateKey() const; public: /** - * @param[in] path Location in the filesystem where leveldb data will be stored. + * @param[in] path Location in the filesystem where leveldb data will + * be stored. * @param[in] nCacheSize Configures various leveldb cache settings. * @param[in] fMemory If true, use leveldb's memory environment. * @param[in] fWipe If true, remove all existing data. - * @param[in] obfuscate If true, store data obfuscated via simple XOR. If false, XOR + * @param[in] obfuscate If true, store data obfuscated via simple XOR. If + * false, XOR * with a zero'd byte array. */ - CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false); + CDBWrapper(const boost::filesystem::path &path, size_t nCacheSize, + bool fMemory = false, bool fWipe = false, + bool obfuscate = false); ~CDBWrapper(); - template - bool Read(const K& key, V& value) const throw(dbwrapper_error) - { + template bool Read(const K &key, V &value) const { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(ssKey.GetSerializeSize(key)); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; - leveldb::Slice slKey(&ssKey[0], ssKey.size()); + leveldb::Slice slKey(ssKey.data(), ssKey.size()); std::string strValue; leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); if (!status.ok()) { - if (status.IsNotFound()) - return false; + if (status.IsNotFound()) return false; LogPrintf("LevelDB read failure: %s\n", status.ToString()); - HandleError(status); + dbwrapper_private::HandleError(status); } try { - CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); + CDataStream ssValue(strValue.data(), + strValue.data() + strValue.size(), SER_DISK, + CLIENT_VERSION); ssValue.Xor(obfuscate_key); ssValue >> value; - } catch (const std::exception&) { + } catch (const std::exception &) { return false; } return true; } template - bool Write(const K& key, const V& value, bool fSync = false) throw(dbwrapper_error) - { - CDBBatch batch(&obfuscate_key); + bool Write(const K &key, const V &value, bool fSync = false) { + CDBBatch batch(*this); batch.Write(key, value); return WriteBatch(batch, fSync); } - template - bool Exists(const K& key) const throw(dbwrapper_error) - { + template bool Exists(const K &key) const { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(ssKey.GetSerializeSize(key)); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; - leveldb::Slice slKey(&ssKey[0], ssKey.size()); + leveldb::Slice slKey(ssKey.data(), ssKey.size()); std::string strValue; leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); if (!status.ok()) { - if (status.IsNotFound()) - return false; + if (status.IsNotFound()) return false; LogPrintf("LevelDB read failure: %s\n", status.ToString()); - HandleError(status); + dbwrapper_private::HandleError(status); } return true; } - template - bool Erase(const K& key, bool fSync = false) throw(dbwrapper_error) - { - CDBBatch batch(&obfuscate_key); + template bool Erase(const K &key, bool fSync = false) { + CDBBatch batch(*this); batch.Erase(key); return WriteBatch(batch, fSync); } - bool WriteBatch(CDBBatch& batch, bool fSync = false) throw(dbwrapper_error); + bool WriteBatch(CDBBatch &batch, bool fSync = false); // not available for LevelDB; provide for compatibility with BDB - bool Flush() - { - return true; - } + bool Flush() { return true; } - bool Sync() throw(dbwrapper_error) - { - CDBBatch batch(&obfuscate_key); + bool Sync() { + CDBBatch batch(*this); return WriteBatch(batch, true); } - CDBIterator *NewIterator() - { - return new CDBIterator(pdb->NewIterator(iteroptions), &obfuscate_key); + CDBIterator *NewIterator() { + return new CDBIterator(*this, pdb->NewIterator(iteroptions)); } /** @@ -264,17 +299,23 @@ class CDBWrapper */ bool IsEmpty(); - /** - * Accessor for obfuscate_key. - */ - const std::vector& GetObfuscateKey() const; - - /** - * Return the obfuscate_key as a hex-formatted string. - */ - std::string GetObfuscateKeyHex() const; - + template + size_t EstimateSize(const K &key_begin, const K &key_end) const { + CDataStream ssKey1(SER_DISK, CLIENT_VERSION), + ssKey2(SER_DISK, CLIENT_VERSION); + ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); + ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); + ssKey1 << key_begin; + ssKey2 << key_end; + leveldb::Slice slKey1(ssKey1.data(), ssKey1.size()); + leveldb::Slice slKey2(ssKey2.data(), ssKey2.size()); + uint64_t size = 0; + leveldb::Range range(slKey1, slKey2); + pdb->GetApproximateSizes(&range, 1, &size); + return size; + } }; + #endif // BITCOIN_DBWRAPPER_H diff --git a/src/bitcoind.cpp b/src/eccoind.cpp similarity index 90% rename from src/bitcoind.cpp rename to src/eccoind.cpp index 5760488b..8db20a37 100644 --- a/src/bitcoind.cpp +++ b/src/eccoind.cpp @@ -3,17 +3,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "chainparams.h" +#include "networks/netman.h" #include "clientversion.h" -#include "rpcserver.h" +#include "rpc/rpcserver.h" #include "init.h" #include "noui.h" #include "scheduler.h" -#include "util.h" +#include "util/util.h" #include "args.h" #include "httpserver.h" #include "httprpc.h" -#include "rpcserver.h" #include #include @@ -74,7 +73,7 @@ bool AppInit(int argc, char* argv[]) // Process help and version before taking care about datadir if (gArgs.IsArgSet("-?") || gArgs.IsArgSet("-h") || gArgs.IsArgSet("-help") || gArgs.IsArgSet("-version")) { - std::string strUsage = _("E-CurrencyCoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n"; + std::string strUsage = _("ECC Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n"; if (gArgs.IsArgSet("-version")) { @@ -83,7 +82,7 @@ bool AppInit(int argc, char* argv[]) else { strUsage += "\n" + _("Usage:") + "\n" + - " eccoind [options] " + _("Start E-CurrencyCoin Core Daemon") + "\n"; + " eccoind [options] " + _("Start ECC Daemon") + "\n"; strUsage += "\n" + HelpMessage(); } @@ -102,24 +101,28 @@ bool AppInit(int argc, char* argv[]) try { gArgs.ReadConfigFile(); - } catch (const std::exception& e) { + } + catch (const std::exception& e) + { fprintf(stderr,"Error reading configuration file: %s\n", e.what()); return false; } // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) try { - SelectParams(ChainNameFromCommandLine()); + CheckParams(ChainNameFromCommandLine()); } catch (const std::exception& e) { fprintf(stderr, "Error: %s\n", e.what()); return false; } - // Command-line RPC bool fCommandLine = false; for (int i = 1; i < argc; i++) - if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "E-CurrencyCoin:")) + { + if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "ECC:")) + { fCommandLine = true; - + } + } if (fCommandLine) { int ret = CommandLineRPC(argc, argv); @@ -129,7 +132,7 @@ bool AppInit(int argc, char* argv[]) fDaemon = gArgs.GetBoolArg("-daemon", false); if (fDaemon) { - fprintf(stdout, "E-CurrencyCoin server starting\n"); + fprintf(stdout, "ECC server starting\n"); // Daemonize pid_t pid = fork(); @@ -150,15 +153,18 @@ bool AppInit(int argc, char* argv[]) } #endif gArgs.SoftSetBoolArg("-server", true); - // Set this early so that parameter interactions go to console InitLogging(); InitParameterInteraction(); + GenerateNetworkTemplates(); fRet = AppInit2(threadGroup, scheduler); } - catch (const std::exception& e) { + catch (const std::exception& e) + { PrintExceptionContinue(&e, "AppInit()"); - } catch (...) { + } + catch (...) + { PrintExceptionContinue(NULL, "AppInit()"); } diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 277c32c2..e55b1142 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -1,19 +1,19 @@ #include "httprpc.h" #include "base58.h" -#include "chainparams.h" +#include "networks/networktemplate.h" #include "httpserver.h" -#include "rpcprotocol.h" -#include "rpcserver.h" +#include "rpc/rpcprotocol.h" +#include "rpc/rpcserver.h" #include "random.h" #include "sync.h" -#include "util.h" +#include "util/util.h" #include "args.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include "ui_interface.h" #include "crypto/hmac_sha256.h" #include -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include // boost::trim diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 6f4acaf4..421ed567 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -2,14 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "compat.h" + #include "httpserver.h" -#include "chainparamsbase.h" -#include "compat.h" -#include "util.h" +#include "networks/netman.h" +#include "init.h" +#include "util/util.h" #include "args.h" #include "netbase.h" -#include "rpcprotocol.h" // For HTTP status codes +#include "rpc/rpcprotocol.h" // For HTTP status codes #include "sync.h" #include "ui_interface.h" @@ -319,7 +321,7 @@ static void ThreadHTTP(struct event_base* base, struct evhttp* http) /** Bind HTTP server to specified addresses */ static bool HTTPBindAddresses(struct evhttp* http) { - int defaultPort = gArgs.GetArg("-rpcport", BaseParams().RPCPort()); + int defaultPort = gArgs.GetArg("-rpcport", pnetMan->getActivePaymentNetwork()->GetRPCPort()); std::vector > endpoints; // Determine what addresses to bind to diff --git a/src/init.cpp b/src/init.cpp index 8b838afd..b1b6f5fe 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -3,17 +3,14 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #include "init.h" #include "addrman.h" #include "amount.h" -#include "chain.h" -#include "chainparams.h" -#include "checkpoints.h" +#include "chain/chain.h" +#include "networks/networktemplate.h" +#include "networks/netman.h" +#include "chain/checkpoints.h" #include "compat/sanity.h" #include "consensus/validation.h" #include "httpserver.h" @@ -23,7 +20,8 @@ #include "miner.h" #include "net.h" #include "policy/policy.h" -#include "rpcserver.h" +#include "processblock.h" +#include "rpc/rpcserver.h" #include "script/standard.h" #include "script/sigcache.h" #include "scheduler.h" @@ -31,18 +29,20 @@ #include "txmempool.h" #include "torcontrol.h" #include "ui_interface.h" -#include "util.h" +#include "util/util.h" #include "args.h" -#include "utilmoneystr.h" -#include "utilstrencodings.h" +#include "util/utilmoneystr.h" +#include "util/utilstrencodings.h" #include "validationinterface.h" - +#include "signals.h" +#include "verifydb.h" #include "wallet/db.h" #include "wallet/wallet.h" #include "wallet/walletdb.h" #include #include +#include #ifndef WIN32 #include @@ -61,6 +61,8 @@ bool fShutdown = false; CWallet* pwalletMain = NULL; +CNetworkManager* pnetMan = NULL; + bool fFeeEstimatesInitialized = false; static const bool DEFAULT_PROXYRANDOMIZE = true; static const bool DEFAULT_REST_ENABLE = false; @@ -128,14 +130,15 @@ bool ShutdownRequested() return fRequestShutdown; } -class CCoinsViewErrorCatcher : public CCoinsViewBacked +class CCoinsViewErrorCatcher final : public CCoinsViewBacked { public: CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {} - bool GetCoins(const uint256 &txid, CCoins &coins) const { + bool GetCoins(const uint256 &txid, CCoins &coins) const override{ try { return CCoinsViewBacked::GetCoins(txid, coins); - } catch(const std::runtime_error& e) { + } catch(const std::runtime_error& e) + { uiInterface.ThreadSafeMessageBox(_("Error reading from database, shutting down."), "", CClientUIInterface::MSG_ERROR); LogPrintf("Error reading from database: %s\n", e.what()); // Starting the shutdown sequence and returning false to the caller would be @@ -148,8 +151,8 @@ class CCoinsViewErrorCatcher : public CCoinsViewBacked // Writes do not need similar protection, as failure to write is handled by the caller. }; -static CCoinsViewDB *pcoinsdbview = NULL; -static CCoinsViewErrorCatcher *pcoinscatcher = NULL; +std::unique_ptr pcoinsdbview; +std::unique_ptr pcoinscatcher; static boost::scoped_ptr globalVerifyHandle; void Interrupt(boost::thread_group& threadGroup) @@ -203,17 +206,23 @@ void Shutdown() { LOCK(cs_main); - if (pcoinsTip != NULL) { - FlushStateToDisk(); + if(pnetMan) + { + if (pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip != NULL) + { + FlushStateToDisk(); + } + pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.reset(); } - delete pcoinsTip; - pcoinsTip = NULL; - delete pcoinscatcher; + pcoinscatcher.reset(); pcoinscatcher = NULL; - delete pcoinsdbview; + pcoinsdbview.reset(); pcoinsdbview = NULL; - delete pblocktree; - pblocktree = NULL; + if(pnetMan) + { + delete pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree; + pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree = NULL; + } } if (pwalletMain) @@ -302,6 +311,7 @@ std::string HelpMessage() strUsage += HelpMessageOpt("-checkblocks=", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), DEFAULT_CHECKBLOCKS)); strUsage += HelpMessageOpt("-checklevel=", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), DEFAULT_CHECKLEVEL)); strUsage += HelpMessageOpt("-conf=", strprintf(_("Specify configuration file (default: %s)"), CONF_FILENAME)); + strUsage += HelpMessageOpt("-returnchange", strprintf(_("Specify if change is returned to same address (default: %u)"), DEFAULT_RETURN_CHANGE)); { #ifndef WIN32 strUsage += HelpMessageOpt("-daemon", _("Run in the background as a daemon and accept commands")); @@ -345,7 +355,7 @@ std::string HelpMessage() strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with bloom filters (default: %u)"), 1)); if (showDebug) strUsage += HelpMessageOpt("-enforcenodebloom", strprintf("Enforce minimum protocol version to limit use of bloom filters (default: %u)", 0)); - strUsage += HelpMessageOpt("-port=", strprintf(_("Listen for connections on (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort())); + strUsage += HelpMessageOpt("-port=", strprintf(_("Listen for connections on (default: %u)"), pnetMan->getActivePaymentNetwork()->GetDefaultPort())); strUsage += HelpMessageOpt("-proxy=", _("Connect through SOCKS5 proxy")); strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE)); strUsage += HelpMessageOpt("-seednode=", _("Connect to a node to retrieve peer addresses, and disconnect")); @@ -394,8 +404,8 @@ std::string HelpMessage() strUsage += HelpMessageOpt("-uacomment=", _("Append comment to the user agent string")); if (showDebug) { - 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=", strprintf("Run checks every transactions (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); + strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", pnetMan->getActivePaymentNetwork()->DefaultConsistencyChecks())); + strUsage += HelpMessageOpt("-checkmempool=", strprintf("Run checks every transactions (default: %u)", pnetMan->getActivePaymentNetwork()->DefaultConsistencyChecks())); strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED)); strUsage += HelpMessageOpt("-dblogsize=", strprintf("Flush wallet database activity from memory to disk log every megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE)); @@ -417,8 +427,7 @@ std::string HelpMessage() _("If is not supplied or if = 1, output all debugging information.") + _(" 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=", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), DEFAULT_GENERATE_THREADS)); + strUsage += HelpMessageOpt("-staking", strprintf(_("Generate coins (default: %u)"), DEFAULT_GENERATE)); 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)); @@ -441,11 +450,13 @@ std::string HelpMessage() } strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)")); - AppendParamsHelpMessages(strUsage, showDebug); - strUsage += HelpMessageGroup(_("Node relay options:")); + + /// TODO: fix this as it is temporarily disabled + /* if (showDebug) - strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard())); + strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CNetMan::TESTNET).RequireStandard())); + */ strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Minimum bytes per sigop in transactions we relay and mine (default: %u)"), DEFAULT_BYTES_PER_SIGOP)); strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER)); strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY)); @@ -466,7 +477,7 @@ std::string HelpMessage() strUsage += HelpMessageOpt("-rpcuser=", _("Username for JSON-RPC connections")); strUsage += HelpMessageOpt("-rpcpassword=", _("Password for JSON-RPC connections")); strUsage += HelpMessageOpt("-rpcauth=", _("Username and hashed password for JSON-RPC connections. The field comes in the format: :$. A canonical python script is included in share/rpcuser. This option can be specified multiple times")); - strUsage += HelpMessageOpt("-rpcport=", strprintf(_("Listen for JSON-RPC connections on (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort())); + strUsage += HelpMessageOpt("-rpcport=", strprintf(_("Listen for JSON-RPC connections on (default: %u)"), pnetMan->getActivePaymentNetwork()->GetRPCPort())); strUsage += HelpMessageOpt("-rpcallowip=", _("Allow JSON-RPC connections from specified source. Valid for are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times")); strUsage += HelpMessageOpt("-rpcthreads=", strprintf(_("Set the number of threads to service RPC calls (default: %d)"), DEFAULT_HTTP_THREADS)); if (showDebug) { @@ -514,54 +525,13 @@ struct CImportingNow } }; - -// If we're using -prune with -reindex, then delete block files that will be ignored by the -// reindex. Since reindexing works by starting at block file 0 and looping until a blockfile -// is missing, do the same here to delete any later block files after a gap. Also delete all -// rev files since they'll be rewritten by the reindex anyway. This ensures that vinfoBlockFile -// is in sync with what's actually on disk by the time we start downloading, so that pruning -// works correctly. -void CleanupBlockRevFiles() -{ - std::map mapBlockFiles; - - // Glob all blk?????.dat and rev?????.dat files from the blocks directory. - // Remove the rev files immediately and insert the blk file paths into an - // ordered map keyed by block file index. - LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n"); - boost::filesystem::path blocksdir = GetDataDir() / "blocks"; - for (boost::filesystem::directory_iterator it(blocksdir); it != boost::filesystem::directory_iterator(); it++) { - if (is_regular_file(*it) && - it->path().filename().string().length() == 12 && - it->path().filename().string().substr(8,4) == ".dat") - { - if (it->path().filename().string().substr(0,3) == "blk") - mapBlockFiles[it->path().filename().string().substr(3,5)] = it->path(); - else if (it->path().filename().string().substr(0,3) == "rev") - remove(it->path()); - } - } - - // Remove all block files that aren't part of a contiguous set starting at - // zero by walking the ordered map (keys are block file indices) by - // keeping a separate counter. Once we hit a gap (or if 0 doesn't exist) - // start removing block files. - int nContigCounter = 0; - for (auto const& item: mapBlockFiles) { - if (atoi(item.first) == nContigCounter) { - nContigCounter++; - continue; - } - remove(item.second); - } -} - void ThreadImport(std::vector vImportFiles) { - const CChainParams& chainparams = Params(); + const CNetworkTemplate& chainparams = pnetMan->getActivePaymentNetwork(); RenameThread("bitcoin-loadblk"); // -reindex - if (fReindex) { + if (fReindex) + { CImportingNow imp; int nFile = 0; while (true) { @@ -572,14 +542,14 @@ void ThreadImport(std::vector vImportFiles) if (!file) break; // This error is logged in OpenBlockFile LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile); - LoadExternalBlockFile(chainparams, file, &pos); + pnetMan->getActivePaymentNetwork()->getChainManager()->LoadExternalBlockFile(chainparams, file, &pos); nFile++; } - pblocktree->WriteReindexing(false); + pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree->WriteReindexing(false); fReindex = false; LogPrintf("Reindexing finished\n"); // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): - InitBlockIndex(chainparams); + pnetMan->getActivePaymentNetwork()->getChainManager()->InitBlockIndex(chainparams); } // hardcoded $DATADIR/bootstrap.dat @@ -590,7 +560,7 @@ void ThreadImport(std::vector vImportFiles) CImportingNow imp; boost::filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; LogPrintf("Importing bootstrap.dat...\n"); - LoadExternalBlockFile(chainparams, file); + pnetMan->getActivePaymentNetwork()->getChainManager()->LoadExternalBlockFile(chainparams, file); RenameOver(pathBootstrap, pathBootstrapOld); } else { LogPrintf("Warning: Could not open bootstrap file %s\n", pathBootstrap.string()); @@ -603,7 +573,7 @@ void ThreadImport(std::vector vImportFiles) if (file) { CImportingNow imp; LogPrintf("Importing blocks file %s...\n", path.string()); - LoadExternalBlockFile(chainparams, file); + pnetMan->getActivePaymentNetwork()->getChainManager()->LoadExternalBlockFile(chainparams, file); } else { LogPrintf("Warning: Could not open blocks file %s\n", path.string()); } @@ -726,7 +696,14 @@ void InitLogging() fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS); LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - LogPrintf("E-CurrencyCoin version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); + LogPrintf("ECC version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); +} + +void GenerateNetworkTemplates() +{ + pnetMan = new CNetworkManager(); + pnetMan->SetParams(ChainNameFromCommandLine()); + } /** Initialize bitcoin. @@ -790,7 +767,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #endif // ********************************************************* Step 2: parameter interactions - const CChainParams& chainparams = Params(); + const CNetworkTemplate& chainparams = pnetMan->getActivePaymentNetwork(); // also see: InitParameterInteraction() @@ -873,14 +850,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (gArgs.IsArgSet("-minrelaytxfee")) { CAmount n = 0; - if (ParseMoney(gArgs.GetArg("-minrelaytxfee", DEFAULT_TRANSACTION_MINFEE), n) && n > 0) + std::string minrelay = gArgs.GetArg("-minrelaytxfee", std::to_string(DEFAULT_TRANSACTION_MINFEE)); + if (ParseMoney(minrelay, n) && n > 0) ::minRelayTxFee = CFeeRate(n); else - return InitError(strprintf(_("Invalid amount for -minrelaytxfee=: '%s'"), gArgs.GetArg("-minrelaytxfee", DEFAULT_TRANSACTION_MINFEE))); + return InitError(strprintf(_("Invalid amount for -minrelaytxfee=: '%i'"), gArgs.GetArg("-minrelaytxfee", DEFAULT_TRANSACTION_MINFEE))); } - fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !Params().RequireStandard()); - if (Params().RequireStandard() && !fRequireStandard) + fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !pnetMan->getActivePaymentNetwork()->RequireStandard()); + if (pnetMan->getActivePaymentNetwork()->RequireStandard() && !fRequireStandard) return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString())); nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp); @@ -888,15 +866,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (gArgs.IsArgSet("-mintxfee")) { CAmount n = 0; - if (ParseMoney(gArgs.GetArg("-mintxfee", DEFAULT_TRANSACTION_MINFEE), n) && n > 0) + std::string minfee = gArgs.GetArg("-mintxfee", std::to_string(DEFAULT_TRANSACTION_MINFEE)); + if (ParseMoney(minfee, n) && n > 0) CWallet::minTxFee = CFeeRate(n); else - return InitError(strprintf(_("Invalid amount for -mintxfee=: '%s'"), gArgs.GetArg("-mintxfee", DEFAULT_TRANSACTION_MINFEE))); + return InitError(strprintf(_("Invalid amount for -mintxfee=: '%i'"), gArgs.GetArg("-mintxfee", DEFAULT_TRANSACTION_MINFEE))); } if (gArgs.IsArgSet("-fallbackfee")) { CAmount nFeePerK = 0; - if (!ParseMoney(gArgs.GetArg("-fallbackfee", DEFAULT_TRANSACTION_MINFEE), nFeePerK)) + std::string fallback = gArgs.GetArg("-fallbackfee", std::to_string(DEFAULT_TRANSACTION_MINFEE)); + if (!ParseMoney(fallback, nFeePerK)) return InitError(strprintf(_("Invalid amount for -fallbackfee=: '%s'"), gArgs.GetArg("-fallbackfee", DEFAULT_TRANSACTION_MINFEE))); if (nFeePerK > nHighTransactionFeeWarning) InitWarning(_("-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.")); @@ -905,28 +885,30 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (gArgs.IsArgSet("-paytxfee")) { CAmount nFeePerK = 0; - if (!ParseMoney(gArgs.GetArg("-paytxfee", DEFAULT_TRANSACTION_MINFEE), nFeePerK)) - return InitError(strprintf(_("Invalid amount for -paytxfee=: '%s'"), gArgs.GetArg("-paytxfee", DEFAULT_TRANSACTION_MINFEE))); + std::string payfee = gArgs.GetArg("-paytxfee", std::to_string(DEFAULT_TRANSACTION_MINFEE)); + if (!ParseMoney(payfee, nFeePerK)) + return InitError(strprintf(_("Invalid amount for -paytxfee=: '%i'"), gArgs.GetArg("-paytxfee", DEFAULT_TRANSACTION_MINFEE))); if (nFeePerK > nHighTransactionFeeWarning) InitWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); payTxFee = CFeeRate(nFeePerK, 1000); if (payTxFee < ::minRelayTxFee) { - return InitError(strprintf(_("Invalid amount for -paytxfee=: '%s' (must be at least %s)"), + return InitError(strprintf(_("Invalid amount for -paytxfee=: '%i' (must be at least %s)"), gArgs.GetArg("-paytxfee", DEFAULT_TRANSACTION_MINFEE), ::minRelayTxFee.ToString())); } } if (gArgs.IsArgSet("-maxtxfee")) { CAmount nMaxFee = 0; - if (!ParseMoney(gArgs.GetArg("-maxtxfee", DEFAULT_TRANSACTION_MAXFEE), nMaxFee)) - return InitError(strprintf(_("Invalid amount for -maxtxfee=: '%s'"), gArgs.GetArg("-maxtxfee", DEFAULT_TRANSACTION_MAXFEE))); + std::string maxfee = gArgs.GetArg("-maxtxfee", std::to_string(DEFAULT_TRANSACTION_MINFEE)); + if (!ParseMoney(maxfee, nMaxFee)) + return InitError(strprintf(_("Invalid amount for -maxtxfee=: '%i'"), gArgs.GetArg("-maxtxfee", DEFAULT_TRANSACTION_MAXFEE))); if (nMaxFee > nHighTransactionMaxFeeWarning) InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); maxTxFee = nMaxFee; if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) { - return InitError(strprintf(_("Invalid amount for -maxtxfee=: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), + return InitError(strprintf(_("Invalid amount for -maxtxfee=: '%i' (must be at least the minrelay fee of %s to prevent stuck transactions)"), gArgs.GetArg("-maxtxfee", DEFAULT_TRANSACTION_MAXFEE), ::minRelayTxFee.ToString())); } } @@ -980,9 +962,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) try { static boost::interprocess::file_lock lock(pathLockFile.string().c_str()); if (!lock.try_lock()) - return InitError(strprintf(_("Cannot obtain a lock on data directory %s. E-CurrencyCoin Core is probably already running."), strDataDir)); + return InitError(strprintf(_("Cannot obtain a lock on data directory %s. ECC is probably already running."), strDataDir)); } catch(const boost::interprocess::interprocess_exception& e) { - return InitError(strprintf(_("Cannot obtain a lock on data directory %s. E-CurrencyCoin Core is probably already running.") + " %s.", strDataDir, e.what())); + return InitError(strprintf(_("Cannot obtain a lock on data directory %s. ECC is probably already running.") + " %s.", strDataDir, e.what())); } #ifndef WIN32 @@ -1222,60 +1204,76 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) std::string strLoadError; uiInterface.InitMessage(_("Loading block index...")); - + LogPrintf("Loading block index..."); nStart = GetTimeMillis(); do { - try { - UnloadBlockIndex(); - delete pcoinsTip; - delete pcoinsdbview; - delete pcoinscatcher; - delete pblocktree; - - pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); - pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex); - pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview); - pcoinsTip = new CCoinsViewCache(pcoinscatcher); + try + { + int64_t lastUpdate = nStart; + pnetMan->getActivePaymentNetwork()->getChainManager()->UnloadBlockIndex(); + pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.reset(); + pcoinsdbview.reset(); + pcoinscatcher.reset(); + delete pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree; + + pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); + pcoinsdbview.reset(new CCoinsViewDB(nCoinDBCache, false, fReset)); + pcoinscatcher.reset(new CCoinsViewErrorCatcher(pcoinsdbview.get())); + pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.reset(new CCoinsViewCache(pcoinscatcher.get())); if (fReindex) { - pblocktree->WriteReindexing(true); + pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree->WriteReindexing(true); } - if (!LoadBlockIndex()) { + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->LoadBlockIndex()) + { strLoadError = _("Error loading block database"); break; } + lastUpdate = GetTimeMillis() - nStart; + LogPrintf("load block index function took %15dms\n", lastUpdate); // If the loaded chain has a wrong genesis, bail out immediately // (we're likely using a testnet datadir, or the other way around). - if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0) + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.empty() && + pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0) return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); // Initialize the block index (no-op if non-empty database was already loaded) - if (!InitBlockIndex(chainparams)) { + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->InitBlockIndex(chainparams)) + { strLoadError = _("Error initializing block database"); break; } - uiInterface.InitMessage(_("Verifying blocks...")); - + //removeImpossibleChainTips(); { - LOCK(cs_main); - CBlockIndex* tip = chainActive.Tip(); - if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) { - strLoadError = _("The block database contains a block which appears to be from the future. " - "This may be due to your computer's date and time being set incorrectly. " - "Only rebuild the block database if you are sure that your computer's date and time are correct"); - break; + uiInterface.InitMessage(_("Verifying blocks...")); + LogPrintf("Verifying blocks..."); + { + LOCK(cs_main); + CBlockIndex* tip = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); + if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) + { + strLoadError = _("The block database contains a block which appears to be from the future. " + "This may be due to your computer's date and time being set incorrectly. " + "Only rebuild the block database if you are sure that your computer's date and time are correct"); + break; + } } - } - if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL), - gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) { - strLoadError = _("Corrupted block database detected"); - break; + if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview.get(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL), + gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) + { + strLoadError = _("Corrupted block database detected"); + break; + } + LogPrintf("verify db function %15dms\n", GetTimeMillis() - lastUpdate); + lastUpdate = GetTimeMillis(); } - } catch (const std::exception& e) { + } + catch (const std::exception& e) + { if (fDebug) LogPrintf("%s\n", e.what()); strLoadError = _("Error opening block database"); break; @@ -1321,7 +1319,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("Shutdown requested. Exiting.\n"); return false; } - LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart); + LogPrintf("total time for block index %15dms\n", GetTimeMillis() - nStart); boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; CAutoFile est_filein(fopen(est_path.string().c_str(), "rb"), SER_DISK, CLIENT_VERSION); @@ -1335,7 +1333,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (fDisableWallet) { pwalletMain = NULL; LogPrintf("Wallet disabled!\n"); - } else { + } + else + { // needed to restore wallet transaction meta data after -zapwallettxes std::vector vWtx; @@ -1360,11 +1360,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) bool fFirstRun = true; pwalletMain = new CWallet(strWalletFile); - /// be very careful with this function. it will be removed in the future. - if (gArgs.IsArgSet("-forceupgradewallet")) - { - pwalletMain->ForceSetMinVersion(20502); - } DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun); if (nLoadWalletRet != DB_LOAD_OK) { @@ -1376,10 +1371,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) " or address book entries might be missing or incorrect.")); } else if (nLoadWalletRet == DB_TOO_NEW) - strErrors << _("Error loading wallet.dat: Wallet requires newer version of E-CurrencyCoin Core") << "\n"; + strErrors << _("Error loading wallet.dat: Wallet requires newer version of ECC") << "\n"; else if (nLoadWalletRet == DB_NEED_REWRITE) { - strErrors << _("Wallet needed to be rewritten: restart E-CurrencyCoin Core to complete") << "\n"; + strErrors << _("Wallet needed to be rewritten: restart ECC to complete") << "\n"; LogPrintf("%s", strErrors.str()); return InitError(strErrors.str()); } @@ -1393,7 +1388,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (nMaxVersion == 0) // the -upgradewallet without argument case { LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST); - nMaxVersion = CLIENT_VERSION; + nMaxVersion = WALLET_VERSION; pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately } else @@ -1415,7 +1410,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) strErrors << _("Cannot write default address") << "\n"; } - pwalletMain->SetBestChain(chainActive.GetLocator()); + pwalletMain->SetBestChain(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.GetLocator()); } LogPrintf("%s", strErrors.str()); @@ -1423,26 +1418,26 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RegisterValidationInterface(pwalletMain); - CBlockIndex *pindexRescan = chainActive.Tip(); + CBlockIndex *pindexRescan = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); if (gArgs.GetBoolArg("-rescan", false)) - pindexRescan = chainActive.Genesis(); + pindexRescan = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Genesis(); else { CWalletDB walletdb(strWalletFile); CBlockLocator locator; if (walletdb.ReadBestBlock(locator)) - pindexRescan = FindForkInGlobalIndex(chainActive, locator); + pindexRescan = pnetMan->getActivePaymentNetwork()->getChainManager()->FindForkInGlobalIndex(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive, locator); else - pindexRescan = chainActive.Genesis(); + pindexRescan = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Genesis(); } - if (chainActive.Tip() && chainActive.Tip() != pindexRescan) + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip() && pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip() != pindexRescan) { uiInterface.InitMessage(_("Rescanning...")); - LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight); + LogPrintf("Rescanning last %i blocks (from block %i)...\n", pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight); nStart = GetTimeMillis(); pwalletMain->ScanForWalletTransactions(pindexRescan, true); LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); - pwalletMain->SetBestChain(chainActive.GetLocator()); + pwalletMain->SetBestChain(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.GetLocator()); nWalletDBUpdated++; // Restore wallet transaction metadata after -zapwallettxes=1 @@ -1479,10 +1474,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) uiInterface.NotifyBlockTip.connect(BlockNotifyCallback); uiInterface.InitMessage(_("Activating best chain...")); + + /// TODO: REMOVE THIS BLOCK OF COMMENTED CODE // scan for better chains in the block chain database, that are not yet connected in the active best chain - CValidationState state; - if (!ActivateBestChain(state, chainparams, LOADED)) - strErrors << "Failed to connect best block"; + //CValidationState state; + //if (!ActivateBestChain(state, chainparams, LOADED)) + // strErrors << "Failed to connect best block"; std::vector vImportFiles; if (gArgs.IsArgSet("-loadblock")) @@ -1491,9 +1488,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) vImportFiles.push_back(strFile); } threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); - if (chainActive.Tip() == NULL) { + /// THIS FOR LOOP IS STUCK FOREVER BECAUSE CHAIN TIP IS NEVER ACTIVATED + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip() == NULL) + { LogPrintf("Waiting for genesis block to be imported...\n"); - while (!fRequestShutdown && chainActive.Tip() == NULL) + while (!fRequestShutdown && pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip() == NULL) MilliSleep(10); } @@ -1508,8 +1507,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RandAddSeedPerfmon(); //// debug print - LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); - LogPrintf("nBestHeight = %d\n", chainActive.Height()); + LogPrintf("mapBlockIndex.size() = %u\n", pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.size()); + LogPrintf("nBestHeight = %d\n", pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height()); LogPrintf("setKeyPool.size() = %u\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0); LogPrintf("mapWallet.size() = %u\n", pwalletMain ? pwalletMain->mapWallet.size() : 0); @@ -1555,3 +1554,5 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return !fRequestShutdown; } + + diff --git a/src/init.h b/src/init.h index 93d06ed4..9e268a39 100644 --- a/src/init.h +++ b/src/init.h @@ -8,6 +8,8 @@ #include #include "wallet/wallet.h" +#include "chain/chainman.h" +#include "networks/netman.h" class CScheduler; class CWallet; @@ -18,6 +20,7 @@ class thread_group; } // namespace boost extern CWallet* pwalletMain; +extern CNetworkManager* pnetMan; void StartShutdown(); bool ShutdownRequested(); @@ -28,6 +31,7 @@ void Shutdown(); void InitLogging(); //!Parameter interaction: change current parameters depending on various rules void InitParameterInteraction(); +void GenerateNetworkTemplates(); bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler); /** Help for options shared between UI and daemon (for -help) */ diff --git a/src/kernel.cpp b/src/kernel.cpp index 87af79fd..81e69b0f 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -5,36 +5,38 @@ #include #include -#include "chain.h" -#include "chainparams.h" +#include "chain/chain.h" +#include "networks/networktemplate.h" +#include "networks/netman.h" #include "consensus/consensus.h" #include "main.h" #include "kernel.h" #include "txdb.h" #include "net.h" #include "crypto/scrypt.h" -#include "utiltime.h" +#include "util/utiltime.h" #include "timedata.h" -#include "args.h"" +#include "args.h" #include "script/stakescript.h" +#include "init.h" // The stake modifier used to hash for a stake kernel is chosen as the stake // modifier about a selection interval later than the coin generating the kernel static bool GetKernelStakeModifier(uint256 hashBlockFrom, uint256& nStakeModifier) { nStakeModifier.SetNull(); - if (!mapBlockIndex.count(hashBlockFrom)) + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(hashBlockFrom)) return error("GetKernelStakeModifier() : block not indexed"); - const CBlockIndex* pindex = mapBlockIndex[hashBlockFrom]; + const CBlockIndex* pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[hashBlockFrom]; int blocksToGo = 5; - if (chainActive.Tip()->nHeight >= 1504350) + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nHeight >= 1504350) { blocksToGo = 180; } - while(chainActive.Next(pindex) && blocksToGo > 0) + while(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Next(pindex) && blocksToGo > 0) { - pindex = chainActive.Next(pindex); + pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Next(pindex); blocksToGo = blocksToGo - 1; } if(blocksToGo > 0) @@ -106,14 +108,14 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, const CTransaction& // First try finding the previous transaction in database CTransaction txPrev; uint256 blockHashOfTx; - if (!GetTransaction(txin.prevout.hash, txPrev, Params().GetConsensus(), blockHashOfTx)) + if (!GetTransaction(txin.prevout.hash, txPrev, pnetMan->getActivePaymentNetwork()->GetConsensus(), blockHashOfTx)) return error("ComputeNextStakeModifier() : INFO: read txPrev failed"); // previous transaction not in main chain, may occur during initial download // Read block header CBlock block; - CBlockIndex* index = mapBlockIndex[blockHashOfTx]; + CBlockIndex* index = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[blockHashOfTx]; - if (!ReadBlockFromDisk(block, index, Params().GetConsensus())) + if (!ReadBlockFromDisk(block, index, pnetMan->getActivePaymentNetwork()->GetConsensus())) return fDebug? error("ComputeNextStakeModifier() : read block failed") : false; // unable to read block of previous transaction if (!GetKernelStakeModifier(block.GetHash(), nStakeModifier)) @@ -156,7 +158,7 @@ bool CheckStakeKernelHash(int nHeight, const CBlock& blockFrom, unsigned int nTx return error("CheckStakeKernelHash() : nTime violation"); unsigned int nTimeBlockFrom = blockFrom.GetBlockTime(); - if (nTimeBlockFrom + Params().getStakeMinAge() > nTimeTx) // Min age requirement + if (nTimeBlockFrom + pnetMan->getActivePaymentNetwork()->getStakeMinAge() > nTimeTx) // Min age requirement return error("CheckStakeKernelHash() : min age violation"); int64_t nValueIn = txPrev.vout[prevout.n].nValue; @@ -164,7 +166,7 @@ bool CheckStakeKernelHash(int nHeight, const CBlock& blockFrom, unsigned int nTx // v0.3 protocol kernel hash weight starts from 0 at the min age // this change increases active coins participating the hash and helps // to secure the network when proof-of-stake difficulty is low - int64_t nTimeWeight = ((int64_t)nTimeTx - txPrev.nTime) - Params().getStakeMinAge(); + int64_t nTimeWeight = ((int64_t)nTimeTx - txPrev.nTime) - pnetMan->getActivePaymentNetwork()->getStakeMinAge(); if(nTimeWeight <= 0) { @@ -211,8 +213,8 @@ bool CheckStakeKernelHash(int nHeight, const CBlock& blockFrom, unsigned int nTx arith_uint256 hashTarget; bool fNegative; bool fOverflow; - hashTarget.SetCompact(GetNextTargetRequired(chainActive.Tip(), true), &fNegative, &fOverflow); - if (fNegative || hashTarget == 0 || fOverflow || hashTarget > UintToArith256(Params().GetConsensus().posLimit)) + hashTarget.SetCompact(GetNextTargetRequired(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(), true), &fNegative, &fOverflow); + if (fNegative || hashTarget == 0 || fOverflow || hashTarget > UintToArith256(pnetMan->getActivePaymentNetwork()->GetConsensus().posLimit)) return error("CheckStakeKernelHash(): nBits below minimum work for proof of stake"); std::string reductionHex = reduction.GetHex(); @@ -264,7 +266,7 @@ bool CheckProofOfStake(int nHeight, const CTransaction& tx, uint256& hashProofOf // First try finding the previous transaction in database CTransaction txPrev; uint256 blockHashOfTx; - if (!GetTransaction(txin.prevout.hash, txPrev, Params().GetConsensus(), blockHashOfTx)) + if (!GetTransaction(txin.prevout.hash, txPrev, pnetMan->getActivePaymentNetwork()->GetConsensus(), blockHashOfTx)) return error("CheckProofOfStake() : INFO: read txPrev failed"); // previous transaction not in main chain, may occur during initial download // Verify signature if (!VerifySignature(txPrev, tx, 0, true)) @@ -272,13 +274,13 @@ bool CheckProofOfStake(int nHeight, const CTransaction& tx, uint256& hashProofOf // Read block header CBlock block; - CBlockIndex* index = mapBlockIndex[blockHashOfTx]; + CBlockIndex* index = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[blockHashOfTx]; - if (!ReadBlockFromDisk(block, index, Params().GetConsensus())) + if (!ReadBlockFromDisk(block, index, pnetMan->getActivePaymentNetwork()->GetConsensus())) return fDebug? error("CheckProofOfStake() : read block failed") : false; // unable to read block of previous transaction CDiskTxPos txindex; - pblocktree->ReadTxIndex(txPrev.GetHash(), txindex); + pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree->ReadTxIndex(txPrev.GetHash(), txindex); if(nHeight < 1505775) { if (!CheckStakeKernelHash(nHeight, block, txindex.nTxOffset + 80, txPrev, txin.prevout, tx.nTime, hashProofOfStake)) diff --git a/src/key.cpp b/src/key.cpp index 09b6b651..a69c4961 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -13,6 +13,8 @@ #include #include + #include + static secp256k1_context* secp256k1_context_sign = nullptr; // Generate a private key from just the secret parameter diff --git a/src/keystore.cpp b/src/keystore.cpp index af70def6..cbd07640 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -7,7 +7,7 @@ #include "key.h" #include "pubkey.h" -#include "util.h" +#include "util/util.h" bool CKeyStore::AddKey(const CKey &key) { return AddKeyPubKey(key, key.GetPubKey()); diff --git a/src/leveldb/db/memtable.cc b/src/leveldb/db/memtable.cc index bfec0a7e..287afdbd 100644 --- a/src/leveldb/db/memtable.cc +++ b/src/leveldb/db/memtable.cc @@ -101,7 +101,7 @@ void MemTable::Add(SequenceNumber s, ValueType type, p += 8; p = EncodeVarint32(p, val_size); memcpy(p, value.data(), val_size); - assert((p + val_size) - buf == encoded_len); + assert(p + val_size == buf + encoded_len); table_.Insert(buf); } diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc index b1256f90..2cb6d80e 100644 --- a/src/leveldb/db/version_set.cc +++ b/src/leveldb/db/version_set.cc @@ -20,7 +20,7 @@ namespace leveldb { -static int TargetFileSize(const Options* options) { +static size_t TargetFileSize(const Options* options) { return options->max_file_size; } diff --git a/src/leveldb/port/atomic_pointer.h b/src/leveldb/port/atomic_pointer.h index 1c4c7aaf..d79a0223 100644 --- a/src/leveldb/port/atomic_pointer.h +++ b/src/leveldb/port/atomic_pointer.h @@ -46,6 +46,30 @@ namespace leveldb { namespace port { +// AtomicPointer based on if available +#if defined(LEVELDB_ATOMIC_PRESENT) +class AtomicPointer { + private: + std::atomic rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + return rep_.load(std::memory_order_acquire); + } + inline void Release_Store(void* v) { + rep_.store(v, std::memory_order_release); + } + inline void* NoBarrier_Load() const { + return rep_.load(std::memory_order_relaxed); + } + inline void NoBarrier_Store(void* v) { + rep_.store(v, std::memory_order_relaxed); + } +}; + +#else + // Define MemoryBarrier() if available // Windows on x86 #if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) @@ -142,28 +166,6 @@ class AtomicPointer { } }; -// AtomicPointer based on -#elif defined(LEVELDB_ATOMIC_PRESENT) -class AtomicPointer { - private: - std::atomic rep_; - public: - AtomicPointer() { } - explicit AtomicPointer(void* v) : rep_(v) { } - inline void* Acquire_Load() const { - return rep_.load(std::memory_order_acquire); - } - inline void Release_Store(void* v) { - rep_.store(v, std::memory_order_release); - } - inline void* NoBarrier_Load() const { - return rep_.load(std::memory_order_relaxed); - } - inline void NoBarrier_Store(void* v) { - rep_.store(v, std::memory_order_relaxed); - } -}; - // Atomic pointer based on sparc memory barriers #elif defined(__sparcv9) && defined(__GNUC__) class AtomicPointer { @@ -228,6 +230,7 @@ class AtomicPointer { #else #error Please implement AtomicPointer for this platform. +#endif #endif #undef LEVELDB_HAVE_MEMORY_BARRIER diff --git a/src/leveldb/port/port_example.h b/src/leveldb/port/port_example.h index 97bd669a..5b1d027d 100644 --- a/src/leveldb/port/port_example.h +++ b/src/leveldb/port/port_example.h @@ -129,6 +129,10 @@ extern bool Snappy_Uncompress(const char* input_data, size_t input_length, // The concatenation of all "data[0,n-1]" fragments is the heap profile. extern bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg); +// Determine whether a working accelerated crc32 implementation exists +// Returns true if AcceleratedCRC32C is safe to call +bool HasAcceleratedCRC32C(); + // Extend the CRC to include the first n bytes of buf. // // Returns zero if the CRC cannot be extended using acceleration, else returns diff --git a/src/leveldb/port/port_posix.cc b/src/leveldb/port/port_posix.cc index 30e8007a..ec39e921 100644 --- a/src/leveldb/port/port_posix.cc +++ b/src/leveldb/port/port_posix.cc @@ -8,6 +8,10 @@ #include #include +#if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__) +#include +#endif + namespace leveldb { namespace port { @@ -49,5 +53,15 @@ void InitOnce(OnceType* once, void (*initializer)()) { PthreadCall("once", pthread_once(once, initializer)); } +bool HasAcceleratedCRC32C() { +#if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__) + unsigned int eax, ebx, ecx, edx; + __get_cpuid(1, &eax, &ebx, &ecx, &edx); + return (ecx & (1 << 20)) != 0; +#else + return false; +#endif +} + } // namespace port } // namespace leveldb diff --git a/src/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h index 7e8213b2..d85fa5d6 100644 --- a/src/leveldb/port/port_posix.h +++ b/src/leveldb/port/port_posix.h @@ -152,6 +152,7 @@ inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { return false; } +bool HasAcceleratedCRC32C(); uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); } // namespace port diff --git a/src/leveldb/port/port_posix_sse.cc b/src/leveldb/port/port_posix_sse.cc index 1e519ba0..2d49c21d 100644 --- a/src/leveldb/port/port_posix_sse.cc +++ b/src/leveldb/port/port_posix_sse.cc @@ -19,7 +19,6 @@ #include #elif defined(__GNUC__) && defined(__SSE4_2__) #include -#include #endif #endif // defined(LEVELDB_PLATFORM_POSIX_SSE) @@ -48,20 +47,6 @@ static inline uint64_t LE_LOAD64(const uint8_t *p) { #endif // defined(_M_X64) || defined(__x86_64__) -static inline bool HaveSSE42() { -#if defined(_MSC_VER) - int cpu_info[4]; - __cpuid(cpu_info, 1); - return (cpu_info[2] & (1 << 20)) != 0; -#elif defined(__GNUC__) - unsigned int eax, ebx, ecx, edx; - __get_cpuid(1, &eax, &ebx, &ecx, &edx); - return (ecx & (1 << 20)) != 0; -#else - return false; -#endif -} - #endif // defined(LEVELDB_PLATFORM_POSIX_SSE) // For further improvements see Intel publication at: @@ -70,10 +55,6 @@ uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size) { #if !defined(LEVELDB_PLATFORM_POSIX_SSE) return 0; #else - static bool have = HaveSSE42(); - if (!have) { - return 0; - } const uint8_t *p = reinterpret_cast(buf); const uint8_t *e = p + size; diff --git a/src/leveldb/port/port_win.cc b/src/leveldb/port/port_win.cc index 1b0f060a..1be9e8d5 100644 --- a/src/leveldb/port/port_win.cc +++ b/src/leveldb/port/port_win.cc @@ -32,6 +32,7 @@ #include #include +#include namespace leveldb { namespace port { @@ -143,5 +144,15 @@ void AtomicPointer::NoBarrier_Store(void* v) { rep_ = v; } +bool HasAcceleratedCRC32C() { +#if defined(__x86_64__) || defined(__i386__) + int cpu_info[4]; + __cpuid(cpu_info, 1); + return (cpu_info[2] & (1 << 20)) != 0; +#else + return false; +#endif +} + } } diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h index 50090048..e8bf46ef 100644 --- a/src/leveldb/port/port_win.h +++ b/src/leveldb/port/port_win.h @@ -168,6 +168,7 @@ inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { return false; } +bool HasAcceleratedCRC32C(); uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); } diff --git a/src/leveldb/util/crc32c.cc b/src/leveldb/util/crc32c.cc index edd61cfd..b3f40eee 100644 --- a/src/leveldb/util/crc32c.cc +++ b/src/leveldb/util/crc32c.cc @@ -288,6 +288,10 @@ static inline uint32_t LE_LOAD32(const uint8_t *p) { // Determine if the CPU running this program can accelerate the CRC32C // calculation. static bool CanAccelerateCRC32C() { + if (!port::HasAcceleratedCRC32C()) + return false; + + // Double-check that the accelerated implementation functions correctly. // port::AcceleretedCRC32C returns zero when unable to accelerate. static const char kTestCRCBuffer[] = "TestCRCBuffer"; static const char kBufSize = sizeof(kTestCRCBuffer) - 1; diff --git a/src/leveldb/util/logging.cc b/src/leveldb/util/logging.cc index ca6b3244..db6160c8 100644 --- a/src/leveldb/util/logging.cc +++ b/src/leveldb/util/logging.cc @@ -49,7 +49,7 @@ bool ConsumeDecimalNumber(Slice* in, uint64_t* val) { uint64_t v = 0; int digits = 0; while (!in->empty()) { - char c = (*in)[0]; + unsigned char c = (*in)[0]; if (c >= '0' && c <= '9') { ++digits; const int delta = (c - '0'); diff --git a/src/main.cpp b/src/main.cpp index 06f0426c..12842ac9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,20 +8,18 @@ #include "addrman.h" #include "arith_uint256.h" #include "bignum.h" -#include "chainparams.h" -#include "checkpoints.h" +#include "networks/networktemplate.h" #include "checkqueue.h" #include "consensus/consensus.h" #include "consensus/merkle.h" #include "consensus/validation.h" -#include "hash.h" +#include "crypto/hash.h" #include "init.h" #include "merkleblock.h" #include "net.h" +#include "networks/netman.h" #include "policy/policy.h" #include "pow.h" -#include "primitives/block.h" -#include "primitives/transaction.h" #include "script/script.h" #include "script/sigcache.h" #include "script/standard.h" @@ -30,19 +28,23 @@ #include "txmempool.h" #include "ui_interface.h" #include "undo.h" -#include "util.h" +#include "util/util.h" #include "args.h" -#include "utilmoneystr.h" -#include "utilstrencodings.h" +#include "util/utilmoneystr.h" +#include "util/utilstrencodings.h" #include "validationinterface.h" #include "versionbits.h" #include "processblock.h" #include "processheader.h" #include "random.h" #include "kernel.h" -#include "chain.h" +#include "chain/chain.h" +#include "chain/checkpoints.h" +#include "processtx.h" +#include #include +#include #include #include #include @@ -52,20 +54,16 @@ #include #include -#if defined(NDEBUG) -# error "Bitcoin cannot be compiled without assertions." -#endif - /** * Global state */ CCriticalSection cs_main; -BlockMap mapBlockIndex; -CChain chainActive; -CBlockIndex *pindexBestHeader = NULL; + int64_t nTimeBestReceived = 0; + + CWaitableCriticalSection csBestBlock; CConditionVariable cvBlockChange; int nScriptCheckThreads = 0; @@ -100,83 +98,59 @@ bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequir /** Constant stuff for coinbase transactions we create: */ CScript COINBASE_FLAGS; -const std::string strMessageMagic = "E-CurrencyCoin Signed Message:\n"; +const std::string strMessageMagic = "ECC Signed Message:\n"; - CBlockIndex *pindexBestInvalid; +CBlockIndex *pindexBestInvalid; /** * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be * missing the data for the block. */ - std::set setBlockIndexCandidates; +std::set setBlockIndexCandidates; + /** Number of nodes with fSyncStarted. */ - int nSyncStarted = 0; +int nSyncStarted = 0; + /** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions. * Pruned nodes may have entries where B is missing data. */ - std::multimap mapBlocksUnlinked; - - CCriticalSection cs_LastBlockFile; - std::vector vinfoBlockFile; - int nLastBlockFile = 0; - /** Global flag to indicate we should check to see if there are - * block/undo files that should be deleted. Set on startup - * or if we allocate more file space when we're in prune mode - */ - bool fCheckForPruning = false; +std::multimap mapBlocksUnlinked; + +CCriticalSection cs_LastBlockFile; +std::vector vinfoBlockFile; +int nLastBlockFile = 0; /** * Every received block is assigned a unique and increasing identifier, so we * know which one to give priority in case of a fork. */ - CCriticalSection cs_nBlockSequenceId; +CCriticalSection cs_nBlockSequenceId; + /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */ - uint32_t nBlockSequenceId = 1; +uint32_t nBlockSequenceId = 1; /** * Sources of received blocks, saved to be able to send them reject * messages or ban them when processing happens afterwards. Protected by * cs_main. */ - std::map mapBlockSource; +std::map mapBlockSource; - /** - * Filter for transactions that were recently rejected by - * AcceptToMemoryPool. These are not rerequested until the chain tip - * changes, at which point the entire filter is reset. Protected by - * cs_main. - * - * Without this filter we'd be re-requesting txs from each of our peers, - * increasing bandwidth consumption considerably. For instance, with 100 - * peers, half of which relay a tx we don't accept, that might be a 50x - * bandwidth increase. A flooding attacker attempting to roll-over the - * filter using minimum-sized, 60byte, transactions might manage to send - * 1000/sec if we have fast peers, so we pick 120,000 to give our peers a - * two minute window to send invs to us. - * - * Decreasing the false positive rate is fairly cheap, so we pick one in a - * million to make it highly unlikely for users to have issues with this - * filter. - * - * Memory used: 1.7MB - */ - boost::scoped_ptr recentRejects; - - std::map::iterator> > mapBlocksInFlight; +std::map::iterator> > mapBlocksInFlight; - /** Number of preferable block download peers. */ - int nPreferredDownload = 0; +/** Number of preferable block download peers. */ +int nPreferredDownload = 0; - /** Dirty block index entries. */ - std::set setDirtyBlockIndex; +/** Dirty block index entries. */ +std::set setDirtyBlockIndex; - /** Dirty block file entries. */ - std::set setDirtyFileInfo; +/** Dirty block file entries. */ +std::set setDirtyFileInfo; - /** Number of peers from which we're downloading blocks. */ - int nPeersWithValidatedDownloads = 0; +/** Number of peers from which we're downloading blocks. */ +int nPeersWithValidatedDownloads = 0; ////////////////////////////////////////////////////////////////////////////// // @@ -198,17 +172,19 @@ CNodeState *State(NodeId pnode) { int GetHeight() { LOCK(cs_main); - return chainActive.Height(); + return pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height(); } -void InitializeNode(NodeId nodeid, const CNode *pnode) { +void InitializeNode(NodeId nodeid, const CNode *pnode) +{ LOCK(cs_main); CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; state.name = pnode->addrName; state.address = pnode->addr; } -void FinalizeNode(NodeId nodeid) { +void FinalizeNode(NodeId nodeid) +{ LOCK(cs_main); CNodeState *state = State(nodeid); @@ -253,42 +229,6 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { return true; } -void RegisterNodeSignals(CNodeSignals& nodeSignals) -{ - nodeSignals.GetHeight.connect(&GetHeight); - nodeSignals.ProcessMessages.connect(&ProcessMessages); - nodeSignals.SendMessages.connect(&SendMessages); - nodeSignals.InitializeNode.connect(&InitializeNode); - nodeSignals.FinalizeNode.connect(&FinalizeNode); -} - -void UnregisterNodeSignals(CNodeSignals& nodeSignals) -{ - nodeSignals.GetHeight.disconnect(&GetHeight); - nodeSignals.ProcessMessages.disconnect(&ProcessMessages); - nodeSignals.SendMessages.disconnect(&SendMessages); - nodeSignals.InitializeNode.disconnect(&InitializeNode); - nodeSignals.FinalizeNode.disconnect(&FinalizeNode); -} - -CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) -{ - // Find the first block the caller has in the main chain - for (auto const& hash: locator.vHave) { - BlockMap::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) - { - CBlockIndex* pindex = (*mi).second; - if (chain.Contains(pindex)) - return pindex; - } - } - return chain.Genesis(); -} - -CCoinsViewCache *pcoinsTip = NULL; -CBlockTreeDB *pblocktree = NULL; - ////////////////////////////////////////////////////////////////////////////// // // mapOrphanTransactions @@ -325,7 +265,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags) // evaluated is what is used. Thus if we want to know if a // transaction can be part of the *next* block, we need to call // IsFinalTx() with one more than chainActive.Height(). - const int nBlockHeight = chainActive.Height() + 1; + const int nBlockHeight = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() + 1; // BIP113 will require that time-locked transactions have nLockTime set to // less than the median time of the previous block they're contained in. @@ -333,7 +273,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags) // chain tip, so we use that to calculate the median time passed to // IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set. const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) - ? chainActive.Tip()->GetMedianTimePast() + ? pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetMedianTimePast() : GetAdjustedTime(); return IsFinalTx(tx, nBlockHeight, nBlockTime); @@ -431,7 +371,7 @@ bool TestLockPointValidity(const LockPoints* lp) 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)) { + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(lp->maxInputBlock)) { return false; } } @@ -445,7 +385,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool AssertLockHeld(cs_main); AssertLockHeld(mempool.cs); - CBlockIndex* tip = chainActive.Tip(); + CBlockIndex* tip = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); CBlockIndex index; index.pprev = tip; // CheckSequenceLocks() uses chainActive.Height()+1 to evaluate @@ -464,7 +404,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool } else { // pcoinsTip contains the UTXO set for chainActive.Tip() - CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); + CCoinsViewMemPool viewMemPool(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get(), mempool); std::vector prevheights; prevheights.resize(tx.vin.size()); for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { @@ -540,61 +480,6 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in return nSigOps; } - - - - - - - -bool CheckTransaction(const CTransaction& tx, CValidationState &state) -{ - // Basic checks that don't depend on any context - if (tx.vin.empty()) - return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty"); - if (tx.vout.empty()) - return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty"); - // Size limits - if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize"); - - // Check for negative or overflow output values - CAmount nValueOut = 0; - for (auto const& txout: tx.vout) - { - if (txout.nValue < 0) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative"); - if (txout.nValue > MAX_MONEY) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge"); - nValueOut += txout.nValue; - if (!MoneyRange(nValueOut)) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge"); - } - - // Check for duplicate inputs - std::set vInOutPoints; - for (auto const& txin: tx.vin) - { - if (vInOutPoints.count(txin.prevout)) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate"); - vInOutPoints.insert(txin.prevout); - } - - if (tx.IsCoinBase()) - { - if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100) - return state.DoS(100, false, REJECT_INVALID, "bad-cb-length"); - } - else - { - for (auto const& txin: tx.vin) - if (txin.prevout.IsNull()) - return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null"); - } - - return true; -} - void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) { int expired = pool.Expire(GetTime() - age); @@ -604,7 +489,7 @@ void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) std::vector vNoSpendsRemaining; pool.TrimToSize(limit, &vNoSpendsRemaining); for(auto const& removed: vNoSpendsRemaining) - pcoinsTip->Uncache(removed); + pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->Uncache(removed); } /** Convert CValidationState to a human-readable message for logging */ @@ -636,14 +521,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C if (fRequireStandard && !IsStandardTx(tx, reason)) return state.DoS(0, false, REJECT_NONSTANDARD, reason); - // Don't relay version 2 transactions until CSV is active, and we can be - // sure that such transactions will be mined (unless we're on - // -testnet/-regtest). - const CChainParams& chainparams = Params(); - if (fRequireStandard && tx.nVersion >= 2 && VersionBitsTipState(chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV) != THRESHOLD_ACTIVE) { - return state.DoS(0, false, REJECT_NONSTANDARD, "premature-version2-tx"); - } - // Only accept nLockTime-using transactions that can be mined in the next // block; we don't want our mempool filled up with transactions that can't // be mined yet. @@ -707,11 +584,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C LockPoints lp; { LOCK(pool.cs); - CCoinsViewMemPool viewMemPool(pcoinsTip, pool); + CCoinsViewMemPool viewMemPool(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get(), pool); view.SetBackend(viewMemPool); // do we already have it? - bool fHadTxInCache = pcoinsTip->HaveCoinsInCache(hash); + bool fHadTxInCache = pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->HaveCoinsInCache(hash); if (view.HaveCoins(hash)) { if (!fHadTxInCache) vHashTxnToUncache.push_back(hash); @@ -722,7 +599,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C // Note that this does not check for the presence of actual outputs (see the next check for that), // and only helps with filling in pfMissingInputs (to determine missing vs spent). for (auto const txin: tx.vin) { - if (!pcoinsTip->HaveCoinsInCache(txin.prevout.hash)) + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->HaveCoinsInCache(txin.prevout.hash)) vHashTxnToUncache.push_back(txin.prevout.hash); if (!view.HaveCoins(txin.prevout.hash)) { if (pfMissingInputs) @@ -767,7 +644,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees); CAmount inChainInputValue; - double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue); + double dPriority = view.GetPriority(tx, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height(), inChainInputValue); // Keep track of transactions that spend a coinbase, which we re-scan // during reorgs to ensure COINBASE_MATURITY is still met. @@ -780,7 +657,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C } } - CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp); + CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp); unsigned int nSize = entry.GetTxSize(); // Check that the transaction doesn't have an excessive number of @@ -795,7 +672,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C CAmount mempoolRejectFee = pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize); if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) { return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee)); - } else if (gArgs.GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) { + } else if (gArgs.GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() + 1))) { // Require that free transactions have sufficient priority to be mined in the next block. return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority"); } @@ -1025,7 +902,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C pool.RemoveStaged(allConflicting); // Store transaction in memory - pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload()); + pool.addUnchecked(hash, entry, setAncestors, !pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload()); // trim mempool and check if tx was trimmed if (!fOverrideMempoolLimit) { @@ -1047,74 +924,11 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, fRejectAbsurdFee, vHashTxToUncache); if (!res) { for (auto const& hashTx: vHashTxToUncache) - pcoinsTip->Uncache(hashTx); + pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->Uncache(hashTx); } return res; } -/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */ -bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow) -{ - CBlockIndex *pindexSlow = NULL; - - LOCK(cs_main); - - if (mempool.lookup(hash, txOut)) - { - return true; - } - - CDiskTxPos postx; - if (pblocktree->ReadTxIndex(hash, postx)) { - CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); - if (file.IsNull()) - return error("%s: OpenBlockFile failed", __func__); - CBlockHeader header; - try { - file >> header; - fseek(file.Get(), postx.nTxOffset, SEEK_CUR); - file >> txOut; - } catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - hashBlock = header.GetHash(); - if (txOut.GetHash() != hash) - return error("%s: txid mismatch", __func__); - return true; - } - - if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it - int nHeight = -1; - { - CCoinsViewCache &view = *pcoinsTip; - const CCoins* coins = view.AccessCoins(hash); - if (coins) - nHeight = coins->nHeight; - } - if (nHeight > 0) - pindexSlow = chainActive[nHeight]; - } - - if (pindexSlow) { - CBlock block; - if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) { - for (auto const& tx: block.vtx) { - if (tx.GetHash() == hash) { - txOut = tx; - hashBlock = pindexSlow->GetBlockHash(); - return true; - } - } - } - } - - return false; -} - - - - - ////////////////////////////////////////////////////////////////////////////// // @@ -1129,7 +943,7 @@ bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHea return error("WriteBlockToDisk: OpenBlockFile failed"); // Write index header - unsigned int nSize = fileout.GetSerializeSize(block); + unsigned int nSize = GetSerializeSize(fileout,block); fileout << FLATDATA(messageStart) << nSize; // Write block @@ -1178,37 +992,6 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus return true; } -CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) -{ - int halvings = nHeight / consensusParams.nSubsidyHalvingInterval; - // Force block reward to zero when right shift is undefined. - if (halvings >= 64) - return 0; - - CAmount nSubsidy = 50 * COIN; - // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years. - nSubsidy >>= halvings; - return nSubsidy; -} - -bool IsInitialBlockDownload() -{ - const CChainParams& chainParams = Params(); - LOCK(cs_main); - if (fImporting || fReindex) - return true; - if (fCheckpointsEnabled && chainActive.Height() < Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints())) - return true; - static bool lockIBDState = false; - if (lockIBDState) - return false; - bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || - pindexBestHeader->GetBlockTime() < GetTime() - chainParams.MaxTipAge()); - if (!state) - lockIBDState = true; - return state; -} - // Requires cs_main. void Misbehaving(NodeId pnode, int howmuch) { @@ -1280,7 +1063,7 @@ bool CScriptCheck::operator()() { int GetSpendHeight(const CCoinsViewCache& inputs) { LOCK(cs_main); - CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; + CBlockIndex* pindexPrev = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(inputs.GetBestBlock())->second; return pindexPrev->nHeight + 1; } @@ -1406,62 +1189,8 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi return true; } -bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart) -{ - // Open history file to append - CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); - if (fileout.IsNull()) - return error("%s: OpenUndoFile failed", __func__); - - // Write index header - unsigned int nSize = fileout.GetSerializeSize(blockundo); - fileout << FLATDATA(messageStart) << nSize; - - // Write undo data - long fileOutPos = ftell(fileout.Get()); - if (fileOutPos < 0) - return error("%s: ftell failed", __func__); - pos.nPos = (unsigned int)fileOutPos; - fileout << blockundo; - - // calculate & write checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - hasher << hashBlock; - hasher << blockundo; - fileout << hasher.GetHash(); - - return true; -} - -bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock) -{ - // Open history file to read - CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); - if (filein.IsNull()) - return error("%s: OpenBlockFile failed", __func__); - - // Read block - uint256 hashChecksum; - try { - filein >> blockundo; - filein >> hashChecksum; - } - catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - - // Verify checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - hasher << hashBlock; - hasher << blockundo; - if (hashChecksum != hasher.GetHash()) - return error("%s: Checksum mismatch", __func__); - - return true; -} - /** Abort with a message */ -bool AbortNode(const std::string& strMessage, const std::string& userMessage="") +bool AbortNode(const std::string& strMessage, const std::string& userMessage) { strMiscWarning = strMessage; LogPrintf("*** %s\n", strMessage); @@ -1478,107 +1207,6 @@ bool AbortNode(CValidationState& state, const std::string& strMessage, const std return state.Error(strMessage); } -/** - * Apply the undo operation of a CTxInUndo to the given chain state. - * @param undo The undo object. - * @param view The coins view to which to apply the changes. - * @param out The out point that corresponds to the tx input. - * @return True on success. - */ -static bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out) -{ - bool fClean = true; - - CCoinsModifier coins = view.ModifyCoins(out.hash); - if (undo.nHeight != 0) { - // undo data contains height: this is the last output of the prevout tx being spent - if (!coins->IsPruned()) - fClean = fClean && error("%s: undo data overwriting existing transaction", __func__); - coins->Clear(); - coins->fCoinBase = undo.fCoinBase; - coins->nHeight = undo.nHeight; - coins->nVersion = undo.nVersion; - } else { - if (coins->IsPruned()) - fClean = fClean && error("%s: undo data adding output to missing transaction", __func__); - } - if (coins->IsAvailable(out.n)) - fClean = fClean && error("%s: undo data overwriting existing output", __func__); - if (coins->vout.size() < out.n+1) - coins->vout.resize(out.n+1); - coins->vout[out.n] = undo.txout; - - return fClean; -} - -bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean) -{ - assert(pindex->GetBlockHash() == view.GetBestBlock()); - - if (pfClean) - *pfClean = false; - - bool fClean = true; - - CBlockUndo blockUndo; - CDiskBlockPos pos = pindex->GetUndoPos(); - if (pos.IsNull()) - return error("DisconnectBlock(): no undo data available"); - if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) - return error("DisconnectBlock(): failure reading undo data"); - - if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) - return error("DisconnectBlock(): block and undo data inconsistent"); - - // undo transactions in reverse order - for (int i = block.vtx.size() - 1; i >= 0; i--) { - const CTransaction &tx = block.vtx[i]; - uint256 hash = tx.GetHash(); - - // Check that all outputs are available and match the outputs in the block itself - // exactly. - { - CCoinsModifier outs = view.ModifyCoins(hash); - outs->ClearUnspendable(); - - CCoins outsBlock(tx, pindex->nHeight); - // The CCoins serialization does not serialize negative numbers. - // No network rules currently depend on the version here, so an inconsistency is harmless - // but it must be corrected before txout nversion ever influences a network rule. - if (outsBlock.nVersion < 0) - outs->nVersion = outsBlock.nVersion; - if (*outs != outsBlock) - fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted"); - - // remove outputs - outs->Clear(); - } - - // restore inputs - if (i > 0) { // not coinbases - const CTxUndo &txundo = blockUndo.vtxundo[i-1]; - if (txundo.vprevout.size() != tx.vin.size()) - return error("DisconnectBlock(): transaction and undo data inconsistent"); - for (unsigned int j = tx.vin.size(); j-- > 0;) { - const COutPoint &out = tx.vin[j].prevout; - const CTxInUndo &undo = txundo.vprevout[j]; - if (!ApplyTxInUndo(undo, view, out)) - fClean = false; - } - } - } - - // move best block pointer to prevout block - view.SetBestBlock(pindex->pprev->GetBlockHash()); - - if (pfClean) { - *pfClean = fClean; - return true; - } - - return fClean; -} - void static FlushBlockFile(bool fFinalize = false) { LOCK(cs_LastBlockFile); @@ -1602,15 +1230,6 @@ void static FlushBlockFile(bool fFinalize = false) } } -bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize); - -static CCheckQueue scriptcheckqueue(128); - -void ThreadScriptCheck() { - RenameThread("bitcoin-scriptch"); - scriptcheckqueue.Thread(); -} - // // Called periodically asynchronously; alerts if it smells like // we're being fed a bad chain (blocks being generated much @@ -1673,7 +1292,7 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const } // Protected by cs_main -static VersionBitsCache versionbitscache; +VersionBitsCache versionbitscache; int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) { @@ -1693,316 +1312,6 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para // Protected by cs_main ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS]; -static int64_t nTimeCheck = 0; -static int64_t nTimeForks = 0; -static int64_t nTimeVerify = 0; -static int64_t nTimeConnect = 0; -static int64_t nTimeIndex = 0; -static int64_t nTimeCallbacks = 0; - -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) -{ - const CChainParams& chainparams = Params(); - AssertLockHeld(cs_main); - - int64_t nTimeStart = GetTimeMicros(); - - if(pindex->GetBlockHash() != chainparams.GetConsensus().hashGenesisBlock) - { - /// once updateForPos runs the only flags that should be enabled are the ones that determine if PoS block or not - /// before this runs there should have been no flags set. so it is ok to reset the flags to 0 - pindex->updateForPos(block); - } - - // Check it again in case a previous version let a bad block in - if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) - return false; - - // verify that the view's current state corresponds to the previous block - uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); - assert(hashPrevBlock == view.GetBestBlock()); - - // Special case for the genesis block, skipping connection of its transactions - // (its coinbase is unspendable) - if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { - if (!fJustCheck) - view.SetBestBlock(pindex->GetBlockHash()); - return true; - } - - bool fScriptChecks = true; - if (fCheckpointsEnabled) { - CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints()); - if (pindexLastCheckpoint && pindexLastCheckpoint->GetAncestor(pindex->nHeight) == pindex) { - // This block is an ancestor of a checkpoint: disable script checks - fScriptChecks = false; - } - } - - - int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart; - LogPrint("bench", " - Sanity checks: %.2fms [%.2fs]\n", 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001); - { - for(auto const& tx: block.vtx) - { - const CCoins* coins = view.AccessCoins(tx.GetHash()); - if (coins && !coins->IsPruned()) - return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"), - REJECT_INVALID, "bad-txns-BIP30"); - } - } - - unsigned int flags = SCRIPT_VERIFY_P2SH; - - // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, - // when 75% of the network has upgraded: - if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { - flags |= SCRIPT_VERIFY_DERSIG; - } - - // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4 - // blocks, when 75% of the network has upgraded: - if (block.nVersion >= 4 && IsSuperMajority(4, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { - flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; - } - - // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic. - int nLockTimeFlags = 0; - if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) { - flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; - nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; - } - - int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1; - LogPrint("bench", " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001); - - CBlockUndo blockundo; - - CCheckQueueControl control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); - - std::vector prevheights; - CAmount nFees = 0; - CAmount nValueIn = 0; - CAmount nValueOut = 0; - int nInputs = 0; - unsigned int nSigOps = 0; - CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); - std::vector > vPos; - vPos.reserve(block.vtx.size()); - blockundo.vtxundo.reserve(block.vtx.size() - 1); - for (unsigned int i = 0; i < block.vtx.size(); i++) - { - const CTransaction &tx = block.vtx[i]; - - nInputs += tx.vin.size(); - nSigOps += GetLegacySigOpCount(tx); - if (nSigOps > MAX_BLOCK_SIGOPS) - return state.DoS(100, error("ConnectBlock(): too many sigops"), - REJECT_INVALID, "bad-blk-sigops"); - - if (tx.IsCoinBase()) - { - nValueOut += tx.GetValueOut(); - } - if (!tx.IsCoinBase()) - { - if (!view.HaveInputs(tx)) - { - return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), - REJECT_INVALID, "bad-txns-inputs-missingorspent"); - } - - // Check that transaction is BIP68 final - // BIP68 lock checks (as opposed to nLockTime checks) must - // be in ConnectBlock because they require the UTXO set - prevheights.resize(tx.vin.size()); - for (size_t j = 0; j < tx.vin.size(); j++) { - prevheights[j] = view.AccessCoins(tx.vin[j].prevout.hash)->nHeight; - } - - if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) { - return state.DoS(100, error("%s: contains a non-BIP68-final transaction", __func__), - REJECT_INVALID, "bad-txns-nonfinal"); - } - - { - // Add in sigops done by pay-to-script-hash inputs; - // this is to prevent a "rogue miner" from creating - // an incredibly-expensive-to-validate block. - nSigOps += GetP2SHSigOpCount(tx, view); - if (nSigOps > MAX_BLOCK_SIGOPS) - return state.DoS(100, error("ConnectBlock(): too many sigops"), - REJECT_INVALID, "bad-blk-sigops"); - } - - CAmount nTxValueIn = view.GetValueIn(tx); - CAmount nTxValueOut = tx.GetValueOut(); - - if (!tx.IsCoinStake()) - { - nFees += nTxValueIn - nTxValueOut; - } - - nValueIn += nTxValueIn; - nValueOut += nTxValueOut; - - std::vector vChecks; - bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ - if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL)) - return error("ConnectBlock(): CheckInputs on %s failed with %s", - tx.GetHash().ToString(), FormatStateMessage(state)); - control.Add(vChecks); - } - - CTxUndo undoDummy; - if (i > 0) { - blockundo.vtxundo.push_back(CTxUndo()); - } - UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); - - vPos.push_back(std::make_pair(tx.GetHash(), pos)); - pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); - } - - - int64_t nTime3 = GetTimeMicros(); - nTimeConnect += nTime3 - nTime2; - LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001); - CAmount blockReward = 0; - - /// after 1504000 no Pow blocks are allowed - if(block.IsProofOfWork() && pindex->nHeight >= 1504000) - { - return state.DoS(100, error("CheckBlock(): proof of work failed, invalid PoW height "), - REJECT_INVALID, "Pow after cutoff"); - } - - /// height >= 1504000 for legacy compatibility - /// someone made some blocks at 1493605 to roughly 1495000 that which didnt conform to the ideal blocks, but at the time the client allowed it - /// that person didnt break any rules and no funds were stolen from other people. - /// but we need to have this check now to prevent future blocks from doing the same thing. - - if(block.IsProofOfWork() && pindex->nHeight >= 1504000) - { - blockReward = GetProofOfWorkReward(nFees, pindex->nHeight, block.hashPrevBlock); - if (block.vtx[0].GetValueOut() > blockReward) - { - return state.DoS(100, - error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", - block.vtx[0].GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); - } - } - else - { - for(auto tx : block.vtx) - { - if(tx.IsCoinStake()) - { - uint64_t nCoinAge; - if (!tx.GetCoinAge(nCoinAge)) - return state.DoS(100, error("ConnectBlock() : %s unable to get coin age for coinstake", tx.GetHash().ToString().substr(0,10).c_str())); - blockReward = blockReward + GetProofOfStakeReward(tx.GetCoinAge(nCoinAge, true), pindex->nHeight); - } - } - if (block.vtx[0].GetValueOut() > blockReward && pindex->nHeight >= 1504000) - { - return state.DoS(100, - error("ConnectBlock(): coinstake pays too much"), REJECT_INVALID, "bad-cb-amount"); - } - } - retry: - if (!control.Wait()) - { - MilliSleep(50); - goto retry; - //return state.DoS(100, false); - } - int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; - LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * 0.000001); - - - // ppcoin: track money supply and mint amount info - pindex->nMint = nValueOut - nValueIn + nFees; - pindex->nMoneySupply = (pindex->pprev? pindex->pprev->nMoneySupply : 0) + nValueOut - nValueIn; - - - /// put the following checks in this function due to lack of pindex when checkblock is called - // Verify hash target and signature of coinstake tx - uint256 hashProofOfStake; - hashProofOfStake.SetNull(); - if (block.IsProofOfStake()) - { - if (!CheckProofOfStake(pindex->nHeight, block.vtx[1], hashProofOfStake)) - { - return state.DoS(100, error("WARNING: ProcessBlock(): check proof-of-stake failed for block %s\n", block.GetHash().ToString().c_str()), REJECT_INVALID, "bad-proofofstake"); - } - } - - // ppcoin: compute stake entropy bit for stake modifier - if (!pindex->SetStakeEntropyBit(block.GetStakeEntropyBit())) - { - return error("AddToBlockIndex() : SetStakeEntropyBit() failed"); - } - // ppcoin: record proof-of-stake hash value - pindex->hashProofOfStake = hashProofOfStake; - - // ppcoin: compute stake modifier - uint256 nStakeModifier; - nStakeModifier.SetNull(); - if(block.IsProofOfStake()) - { - if (!ComputeNextStakeModifier(pindex->pprev, block.vtx[1], nStakeModifier)) - return state.DoS(100, error("ConnectBlock() : ComputeNextStakeModifier() failed") , REJECT_INVALID, "bad-stakemodifier-pos"); - } - else - { - if (!ComputeNextStakeModifier(pindex->pprev, block.vtx[0], nStakeModifier)) - return state.DoS(100, error("ConnectBlock() : ComputeNextStakeModifier() failed"), REJECT_INVALID, "bad-stakemodifier-pow"); - } - pindex->SetStakeModifier(nStakeModifier); - if (fJustCheck) - return true; - - // Write undo information to disk - if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) - { - if (pindex->GetUndoPos().IsNull()) { - CDiskBlockPos pos; - if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40)) - return error("ConnectBlock(): FindUndoPos failed"); - if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) - return AbortNode(state, "Failed to write undo data"); - - // update nUndoPos in block index - pindex->nUndoPos = pos.nPos; - pindex->nStatus |= BLOCK_HAVE_UNDO; - } - pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); - setDirtyBlockIndex.insert(pindex); - } - - if (!pblocktree->WriteTxIndex(vPos)) - { - return AbortNode(state, "Failed to write transaction index"); - } - - // add this block to the view's block chain - view.SetBestBlock(pindex->GetBlockHash()); - - int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4; - LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001); - - // Watch for changes to the previous coinbase transaction. - static uint256 hashPrevBestCoinBase; - GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); - hashPrevBestCoinBase = block.vtx[0].GetHash(); - - int64_t nTime6 = GetTimeMicros(); nTimeCallbacks += nTime6 - nTime5; - LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001); - - return true; -} - /** * Update the on-disk chain state. * The caches and indexes are flushed depending on the mode we're called with @@ -2011,13 +1320,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin */ bool FlushStateToDisk(CValidationState &state, FlushStateMode mode) { - const CChainParams& chainparams = Params(); LOCK2(cs_main, cs_LastBlockFile); static int64_t nLastWrite = 0; static int64_t nLastFlush = 0; static int64_t nLastSetChain = 0; - std::set setFilesToPrune; - bool fFlushForPrune = false; try { int64_t nNow = GetTimeMicros(); @@ -2031,7 +1337,7 @@ bool FlushStateToDisk(CValidationState &state, FlushStateMode mode) if (nLastSetChain == 0) { nLastSetChain = nNow; } - size_t cacheSize = pcoinsTip->DynamicMemoryUsage(); + size_t cacheSize = pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->DynamicMemoryUsage(); // The cache is large and close to the limit, but we have time now (not in the middle of a block processing). bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0/9) > nCoinCacheUsage; // The cache is over the limit, we have to write now. @@ -2041,7 +1347,7 @@ bool FlushStateToDisk(CValidationState &state, FlushStateMode mode) // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage. bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000; // Combine all conditions that result in a full cache flush. - bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune; + bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush; // Write blocks and block index to disk. if (fDoFullFlush || fPeriodicWrite) { // Depend on nMinDiskSpace to ensure we can write block index @@ -2063,13 +1369,10 @@ bool FlushStateToDisk(CValidationState &state, FlushStateMode mode) vBlocks.push_back(*it); setDirtyBlockIndex.erase(it++); } - if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) { + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) { return AbortNode(state, "Files to write to block index database"); } } - // Finally remove any pruned files - if (fFlushForPrune) - UnlinkPrunedFiles(setFilesToPrune); nLastWrite = nNow; } // Flush best chain related state. This can only be done if the blocks / block index write was also done. @@ -2079,16 +1382,16 @@ bool FlushStateToDisk(CValidationState &state, FlushStateMode mode) // twice (once in the log, and once in the tables). This is already // an overestimation, as most will delete an existing entry or // overwrite one. Still, use a conservative safety factor of 2. - if (!CheckDiskSpace(128 * 2 * 2 * pcoinsTip->GetCacheSize())) + if (!CheckDiskSpace(128 * 2 * 2 * pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->GetCacheSize())) return state.Error("out of disk space"); // Flush the chainstate (which may refer to block index entries). - if (!pcoinsTip->Flush()) + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->Flush()) return AbortNode(state, "Failed to write to coin database"); nLastFlush = nNow; } if (fDoFullFlush || ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) { // Update best block in wallet (so we can detect restored wallets). - GetMainSignals().SetBestChain(chainActive.GetLocator()); + GetMainSignals().SetBestChain(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.GetLocator()); nLastSetChain = nNow; } } catch (const std::runtime_error& e) @@ -2103,19 +1406,13 @@ void FlushStateToDisk() { FlushStateToDisk(state, FLUSH_STATE_ALWAYS); } -void PruneAndFlush() { - CValidationState state; - fCheckForPruning = true; - FlushStateToDisk(state, FLUSH_STATE_NONE); -} - /** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */ void PruneBlockIndexCandidates() { // Note that we can't delete the current block itself, as we may need to return to it later in case a // reorganization to a better block fails. std::set::iterator it = setBlockIndexCandidates.begin(); - while (it != setBlockIndexCandidates.end() && setBlockIndexCandidates.value_comp()(*it, chainActive.Tip())) { + while (it != setBlockIndexCandidates.end() && setBlockIndexCandidates.value_comp()(*it, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip())) { setBlockIndexCandidates.erase(it++); } // Either the current tip or a successor of it we're working towards is left in setBlockIndexCandidates. @@ -2132,15 +1429,15 @@ bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensus setDirtyBlockIndex.insert(pindex); setBlockIndexCandidates.erase(pindex); - while (chainActive.Contains(pindex)) { - CBlockIndex *pindexWalk = chainActive.Tip(); + while (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(pindex)) { + CBlockIndex *pindexWalk = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); pindexWalk->nStatus |= BLOCK_FAILED_CHILD; setDirtyBlockIndex.insert(pindexWalk); setBlockIndexCandidates.erase(pindexWalk); // ActivateBestChain considers blocks already in chainActive // unconditionally valid already, so force disconnect away from it. if (!DisconnectTip(state, consensusParams)) { - mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); + mempool.removeForReorg(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get(), pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); return false; } } @@ -2149,16 +1446,16 @@ bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensus // The resulting new best tip may not be in setBlockIndexCandidates anymore, so // add it again. - BlockMap::iterator it = mapBlockIndex.begin(); - while (it != mapBlockIndex.end()) { - if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) { + BlockMap::iterator it = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.begin(); + while (it != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) { + if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip())) { setBlockIndexCandidates.insert(it->second); } it++; } InvalidChainFound(pindex); - mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); + mempool.removeForReorg(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get(), pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); return true; } @@ -2168,12 +1465,12 @@ bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) { int nHeight = pindex->nHeight; // Remove the invalidity flag from this block and all its descendants. - BlockMap::iterator it = mapBlockIndex.begin(); - while (it != mapBlockIndex.end()) { + BlockMap::iterator it = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.begin(); + while (it != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) { if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) { it->second->nStatus &= ~BLOCK_FAILED_MASK; setDirtyBlockIndex.insert(it->second); - if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) { + if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(), it->second)) { setBlockIndexCandidates.insert(it->second); } if (it->second == pindexBestInvalid) { @@ -2195,40 +1492,6 @@ bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) { return true; } -CBlockIndex* AddToBlockIndex(const CBlockHeader& block) -{ - // Check for duplicate - uint256 hash = block.GetHash(); - BlockMap::iterator it = mapBlockIndex.find(hash); - if (it != mapBlockIndex.end()) - return it->second; - - // Construct new block index object - CBlockIndex* pindexNew = new CBlockIndex(block); - assert(pindexNew); - // We assign the sequence id to blocks only when the full data is available, - // to avoid miners withholding blocks but broadcasting headers, to get a - // competitive advantage. - pindexNew->nSequenceId = 0; - BlockMap::iterator mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first; - pindexNew->phashBlock = &((*mi).first); - BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); - if (miPrev != mapBlockIndex.end()) - { - pindexNew->pprev = (*miPrev).second; - pindexNew->nHeight = pindexNew->pprev->nHeight + 1; - pindexNew->BuildSkip(); - } - pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); - pindexNew->RaiseValidity(BLOCK_VALID_TREE); - if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork) - pindexBestHeader = pindexNew; - - setDirtyBlockIndex.insert(pindexNew); - - return pindexNew; -} - /** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos) { @@ -2255,7 +1518,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl LOCK(cs_nBlockSequenceId); pindex->nSequenceId = nBlockSequenceId++; } - if (chainActive.Tip() == NULL || !setBlockIndexCandidates.value_comp()(pindex, chainActive.Tip())) { + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip() == NULL || !setBlockIndexCandidates.value_comp()(pindex, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip())) { setBlockIndexCandidates.insert(pindex); } std::pair::iterator, std::multimap::iterator> range = mapBlocksUnlinked.equal_range(pindex); @@ -2275,7 +1538,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl return true; } -bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false) +bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown) { LOCK(cs_LastBlockFile); @@ -2330,35 +1593,6 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd return true; } -bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize) -{ - pos.nFile = nFile; - - LOCK(cs_LastBlockFile); - - unsigned int nNewSize; - pos.nPos = vinfoBlockFile[nFile].nUndoSize; - nNewSize = vinfoBlockFile[nFile].nUndoSize += nAddSize; - setDirtyFileInfo.insert(nFile); - - unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; - unsigned int nNewChunks = (nNewSize + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; - if (nNewChunks > nOldChunks) { - if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) { - FILE *file = OpenUndoFile(pos); - if (file) { - LogPrintf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); - AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); - fclose(file); - } - } - else - return state.Error("out of disk space"); - } - - return true; -} - bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot) { @@ -2367,7 +1601,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo if (block.fChecked) return true; - if (block.IsProofOfWork() && fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) + if (block.IsProofOfWork() && fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, pnetMan->getActivePaymentNetwork()->GetConsensus())) return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), REJECT_INVALID, "high-hash"); @@ -2454,7 +1688,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo return true; } -bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams, const uint256& hash) +bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CNetworkTemplate& chainparams, const uint256& hash) { if (*pindexPrev->phashBlock == chainparams.GetConsensus().hashGenesisBlock) return true; @@ -2471,21 +1705,21 @@ bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex * const pindexPrev) { const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; - const Consensus::Params& consensusParams = Params().GetConsensus(); + const Consensus::Params& consensusParams = pnetMan->getActivePaymentNetwork()->GetConsensus(); // Start enforcing BIP113 (Median Time Past) using versionbits logic. int nLockTimeFlags = 0; - if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) { - nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST; - } + nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST; int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST) ? pindexPrev->GetMedianTimePast() : block.GetBlockTime(); // Check that all transactions are finalized - for (auto const& tx: block.vtx) { - if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { + for (auto const& tx: block.vtx) + { + if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) + { return state.DoS(10, error("%s: contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); } } @@ -2505,70 +1739,6 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn } -/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */ -bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) -{ - AssertLockHeld(cs_main); - - CBlockIndex *&pindex = *ppindex; - - if (!AcceptBlockHeader(block, state, chainparams, &pindex)) - return false; - - // Try to process all requested blocks that we don't have, but only - // process an unrequested block if it's new and has enough work to - // advance our tip, and isn't too many blocks ahead. - bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA; - bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true); - // Blocks that are too out-of-order needlessly limit the effectiveness of - // pruning, because pruning will not delete block files that contain any - // blocks which are too close in height to the tip. Apply this test - // regardless of whether pruning is enabled; it should generally be safe to - // not process unrequested blocks. - bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP)); - - // TODO: deal better with return value and error conditions for duplicate - // and unrequested blocks. - if (fAlreadyHave) return true; - if (!fRequested) { // If we didn't ask for it: - if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned - if (!fHasMoreWork) return true; // Don't process less-work chains - if (fTooFarAhead) return true; // Block height is too high - } - - if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) { - if (state.IsInvalid() && !state.CorruptionPossible()) { - pindex->nStatus |= BLOCK_FAILED_VALID; - setDirtyBlockIndex.insert(pindex); - } - return false; - } - - int nHeight = pindex->nHeight; - - // Write block to history file - try { - unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); - CDiskBlockPos blockPos; - if (dbp != NULL) - blockPos = *dbp; - if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL)) - return error("AcceptBlock(): FindBlockPos failed"); - if (dbp == NULL) - if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) - AbortNode(state, "Failed to write block"); - if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) - return error("AcceptBlock(): ReceivedBlockTransactions failed"); - } catch (const std::runtime_error& e) { - return AbortNode(state, std::string("System error: ") + e.what()); - } - - if (fCheckForPruning) - FlushStateToDisk(state, FLUSH_STATE_NONE); // we just allocated more disk space for block files - - return true; -} - bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams) { unsigned int nFound = 0; @@ -2596,16 +1766,6 @@ uint64_t CalculateCurrentUsage() return retval; } -void UnlinkPrunedFiles(std::set& setFilesToPrune) -{ - for (std::set::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) { - CDiskBlockPos pos(*it, 0); - boost::filesystem::remove(GetBlockPosFilename(pos, "blk")); - boost::filesystem::remove(GetBlockPosFilename(pos, "rev")); - LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, *it); - } -} - bool CheckDiskSpace(uint64_t nAdditionalBytes) { uint64_t nFreeBytesAvailable = boost::filesystem::space(GetDataDir()).available; @@ -2623,7 +1783,7 @@ FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) return NULL; boost::filesystem::path path = GetBlockPosFilename(pos, prefix); boost::filesystem::create_directories(path.parent_path()); - FILE* file = fopen(path.string().c_str(), "rb+"); + FILE* file = fopen(path.string().c_str(), fReadOnly ? "rb": "rb+"); if (!file && !fReadOnly) file = fopen(path.string().c_str(), "wb+"); if (!file) { @@ -2653,412 +1813,7 @@ boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile); } -CBlockIndex * InsertBlockIndex(uint256 hash) -{ - if (hash.IsNull()) - return NULL; - - // Return existing - BlockMap::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) - return (*mi).second; - - // Create new - CBlockIndex* pindexNew = new CBlockIndex(); - if (!pindexNew) - throw std::runtime_error("LoadBlockIndex(): new CBlockIndex failed"); - mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first; - pindexNew->phashBlock = &((*mi).first); - - return pindexNew; -} - -bool static LoadBlockIndexDB() -{ - const CChainParams& chainparams = Params(); - if (!pblocktree->LoadBlockIndexGuts()) - return false; - - boost::this_thread::interruption_point(); - - // Calculate nChainWork - std::vector > vSortedByHeight; - vSortedByHeight.reserve(mapBlockIndex.size()); - for (auto const& item: mapBlockIndex) - { - CBlockIndex* pindex = item.second; - vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex)); - } - std::sort(vSortedByHeight.begin(), vSortedByHeight.end()); - for (auto const& item: vSortedByHeight) - { - CBlockIndex* pindex = item.second; - pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex); - // We can link the chain of blocks for which we've received transactions at some point. - // Pruned nodes may have deleted the block. - if (pindex->nTx > 0) { - if (pindex->pprev) { - if (pindex->pprev->nChainTx) { - pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx; - } else { - pindex->nChainTx = 0; - mapBlocksUnlinked.insert(std::make_pair(pindex->pprev, pindex)); - } - } else { - pindex->nChainTx = pindex->nTx; - } - } - if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL)) - setBlockIndexCandidates.insert(pindex); - if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork)) - pindexBestInvalid = pindex; - if (pindex->pprev) - pindex->BuildSkip(); - if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == NULL || CBlockIndexWorkComparator()(pindexBestHeader, pindex))) - pindexBestHeader = pindex; - } - - // Load block file info - pblocktree->ReadLastBlockFile(nLastBlockFile); - vinfoBlockFile.resize(nLastBlockFile + 1); - LogPrintf("%s: last block file = %i\n", __func__, nLastBlockFile); - for (int nFile = 0; nFile <= nLastBlockFile; nFile++) { - pblocktree->ReadBlockFileInfo(nFile, vinfoBlockFile[nFile]); - } - LogPrintf("%s: last block file info: %s\n", __func__, vinfoBlockFile[nLastBlockFile].ToString()); - for (int nFile = nLastBlockFile + 1; true; nFile++) { - CBlockFileInfo info; - if (pblocktree->ReadBlockFileInfo(nFile, info)) { - vinfoBlockFile.push_back(info); - } else { - break; - } - } - - // Check presence of blk files - LogPrintf("Checking all blk files are present...\n"); - std::set setBlkDataFiles; - for (auto const& item: mapBlockIndex) - { - CBlockIndex* pindex = item.second; - if (pindex->nStatus & BLOCK_HAVE_DATA) { - setBlkDataFiles.insert(pindex->nFile); - } - } - for (std::set::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) - { - CDiskBlockPos pos(*it, 0); - if (CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION).IsNull()) { - return false; - } - } - - // Check whether we need to continue reindexing - bool fReindexing = false; - pblocktree->ReadReindexing(fReindexing); - fReindex |= fReindexing; - - // Load pointer to end of best chain - BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); - if (it == mapBlockIndex.end()) - return true; - chainActive.SetTip(it->second); - - PruneBlockIndexCandidates(); - - LogPrintf("%s: hashBestChain=%s height=%d date=%s progress=%f\n", __func__, - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainparams.Checkpoints(), chainActive.Tip())); - - return true; -} - -CVerifyDB::CVerifyDB() -{ - uiInterface.ShowProgress(_("Verifying blocks..."), 0); -} - -CVerifyDB::~CVerifyDB() -{ - uiInterface.ShowProgress("", 100); -} -bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) -{ - LOCK(cs_main); - if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL) - return true; - - // Verify blocks in the best chain - if (nCheckDepth <= 0) - nCheckDepth = 1000000000; // suffices until the year 19000 - if (nCheckDepth > chainActive.Height()) - nCheckDepth = chainActive.Height(); - nCheckLevel = std::max(0, std::min(4, nCheckLevel)); - LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); - CCoinsViewCache coins(coinsview); - CBlockIndex* pindexState = chainActive.Tip(); - CBlockIndex* pindexFailure = NULL; - int nGoodTransactions = 0; - CValidationState state; - for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) - { - boost::this_thread::interruption_point(); - uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))))); - if (pindex->nHeight < chainActive.Height()-nCheckDepth) - break; - CBlock block; - // check level 0: read from disk - if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) - return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - // check level 1: verify block validity - if (nCheckLevel >= 1 && !CheckBlock(block, state)) - return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); - // check level 2: verify undo validity - if (nCheckLevel >= 2 && pindex) { - CBlockUndo undo; - CDiskBlockPos pos = pindex->GetUndoPos(); - if (!pos.IsNull()) { - if (!UndoReadFromDisk(undo, pos, pindex->pprev->GetBlockHash())) - return error("VerifyDB(): *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); - } - } - // check level 3: check for inconsistencies during memory-only disconnect of tip blocks - if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) { - bool fClean = true; - if (!DisconnectBlock(block, state, pindex, coins, &fClean)) - return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - pindexState = pindex->pprev; - if (!fClean) { - nGoodTransactions = 0; - pindexFailure = pindex; - } else - nGoodTransactions += block.vtx.size(); - } - if (ShutdownRequested()) - return true; - } - if (pindexFailure) - return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions); - - // check level 4: try reconnecting blocks - if (nCheckLevel >= 4) { - CBlockIndex *pindex = pindexState; - while (pindex != chainActive.Tip()) { - boost::this_thread::interruption_point(); - uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)))); - pindex = chainActive.Next(pindex); - CBlock block; - if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) - return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - if (!ConnectBlock(block, state, pindex, coins)) - return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - } - } - - LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->nHeight, nGoodTransactions); - - return true; -} - -void UnloadBlockIndex() -{ - LOCK(cs_main); - setBlockIndexCandidates.clear(); - chainActive.SetTip(NULL); - pindexBestInvalid = NULL; - pindexBestHeader = NULL; - mempool.clear(); - mapOrphanTransactions.clear(); - mapOrphanTransactionsByPrev.clear(); - nSyncStarted = 0; - mapBlocksUnlinked.clear(); - vinfoBlockFile.clear(); - nLastBlockFile = 0; - nBlockSequenceId = 1; - mapBlockSource.clear(); - mapBlocksInFlight.clear(); - nPreferredDownload = 0; - setDirtyBlockIndex.clear(); - setDirtyFileInfo.clear(); - mapNodeState.clear(); - recentRejects.reset(NULL); - versionbitscache.Clear(); - for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) { - warningcache[b].clear(); - } - - for (auto& entry: mapBlockIndex) { - delete entry.second; - } - mapBlockIndex.clear(); -} - -bool LoadBlockIndex() -{ - // Load block index from databases - if (!fReindex && !LoadBlockIndexDB()) - return false; - return true; -} - -bool InitBlockIndex(const CChainParams& chainparams) -{ - LOCK(cs_main); - - // Initialize global variables that cannot be constructed at startup. - recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); - - // Check whether we're already initialized - if (chainActive.Genesis() != NULL) - return true; - - // Use the provided setting for -txindex in the new database - pblocktree->WriteFlag("txindex", true); - LogPrintf("Initializing databases...\n"); - - // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) - if (!fReindex) { - try { - CBlock &block = const_cast(chainparams.GenesisBlock()); - // Start new block file - unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); - CDiskBlockPos blockPos; - CValidationState state; - if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime())) - return error("InitBlockIndex(): FindBlockPos failed"); - if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) - return error("InitBlockIndex(): writing genesis block to disk failed"); - CBlockIndex *pindex = AddToBlockIndex(block); - - // ppcoin: compute stake entropy bit for stake modifier - if (!pindex->SetStakeEntropyBit(block.GetStakeEntropyBit())) - { - return error("InitBlockIndex() : SetStakeEntropyBit() failed"); - } - // ppcoin: compute stake modifier - uint256 nStakeModifier; - nStakeModifier.SetNull(); - CTransaction nullTx; - if (!ComputeNextStakeModifier(pindex->pprev, nullTx, nStakeModifier)) - return error("InitBlockIndex() : ComputeNextStakeModifier() failed"); - pindex->SetStakeModifier(nStakeModifier); - if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) - return error("InitBlockIndex(): genesis block not accepted"); - if (!ActivateBestChain(state, chainparams, LOADED, &block)) - return error("InitBlockIndex(): genesis block cannot be activated"); - // Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data - return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); - } catch (const std::runtime_error& e) { - return error("InitBlockIndex(): failed to initialize block database: %s", e.what()); - } - } - - return true; -} - -bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp) -{ - // std::map of disk positions for blocks with unknown parent (only used for reindex) - static std::multimap mapBlocksUnknownParent; - int64_t nStart = GetTimeMillis(); - - int nLoaded = 0; - try { - // This takes over fileIn and calls fclose() on it in the CBufferedFile destructor - CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); - uint64_t nRewind = blkdat.GetPos(); - while (!blkdat.eof()) { - boost::this_thread::interruption_point(); - - blkdat.SetPos(nRewind); - nRewind++; // start one byte further next time, in case of failure - blkdat.SetLimit(); // remove former limit - unsigned int nSize = 0; - try { - // locate a header - unsigned char buf[MESSAGE_START_SIZE]; - blkdat.FindByte(chainparams.MessageStart()[0]); - nRewind = blkdat.GetPos()+1; - blkdat >> FLATDATA(buf); - if (memcmp(buf, chainparams.MessageStart(), MESSAGE_START_SIZE)) - continue; - // read size - blkdat >> nSize; - if (nSize < 80 || nSize > MAX_BLOCK_SIZE) - continue; - } catch (const std::exception&) { - // no valid block header found; don't complain - break; - } - try { - // read block - uint64_t nBlockPos = blkdat.GetPos(); - if (dbp) - dbp->nPos = nBlockPos; - blkdat.SetLimit(nBlockPos + nSize); - blkdat.SetPos(nBlockPos); - CBlock block; - blkdat >> block; - nRewind = blkdat.GetPos(); - - // detect out of order blocks, and store them for later - uint256 hash = block.GetHash(); - if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { - LogPrint("reindex", "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), - block.hashPrevBlock.ToString()); - if (dbp) - mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp)); - continue; - } - - // process in case the block isn't known yet - if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { - CValidationState state; - if (ProcessNewBlock(state, chainparams, NULL, &block, true, dbp, LOADED)) - nLoaded++; - if (state.IsError()) - break; - } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { - LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); - } - - // Recursively process earlier encountered successors of this block - std::deque queue; - queue.push_back(hash); - while (!queue.empty()) { - uint256 head = queue.front(); - queue.pop_front(); - std::pair::iterator, std::multimap::iterator> range = mapBlocksUnknownParent.equal_range(head); - while (range.first != range.second) { - std::multimap::iterator it = range.first; - if (ReadBlockFromDisk(block, it->second, chainparams.GetConsensus())) - { - LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), - head.ToString()); - CValidationState dummy; - if (ProcessNewBlock(dummy, chainparams, NULL, &block, true, &it->second, LOADED)) - { - nLoaded++; - queue.push_back(block.GetHash()); - } - } - range.first++; - mapBlocksUnknownParent.erase(it); - } - } - } catch (const std::exception& e) { - LogPrintf("%s: Deserialize or I/O error - %s\n", __func__, e.what()); - } - } - } catch (const std::runtime_error& e) { - AbortNode(std::string("System error: ") + e.what()); - } - if (nLoaded > 0) - LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, GetTimeMillis() - nStart); - return nLoaded > 0; -} ////////////////////////////////////////////////////////////////////////////// // @@ -3113,20 +1868,15 @@ std::string CBlockFileInfo::ToString() const { ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos) { LOCK(cs_main); - return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache); + return VersionBitsState(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(), params, pos, versionbitscache); } class CMainCleanup { public: CMainCleanup() {} - ~CMainCleanup() { - // block headers - BlockMap::iterator it1 = mapBlockIndex.begin(); - for (; it1 != mapBlockIndex.end(); it1++) - delete (*it1).second; - mapBlockIndex.clear(); - + ~CMainCleanup() + { // orphan transactions mapOrphanTransactions.clear(); mapOrphanTransactionsByPrev.clear(); @@ -3144,12 +1894,12 @@ const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfSta unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake) { - CBigNum bnTargetLimit = CBigNum(Params().GetConsensus().powLimit); + CBigNum bnTargetLimit = CBigNum(pnetMan->getActivePaymentNetwork()->GetConsensus().powLimit); if(fProofOfStake) { // Proof-of-Stake blocks has own target limit since nVersion=3 supermajority on mainNet and always on testNet - bnTargetLimit = CBigNum(Params().GetConsensus().posLimit); + bnTargetLimit = CBigNum(pnetMan->getActivePaymentNetwork()->GetConsensus().posLimit); } if (pindexLast == NULL) @@ -3167,9 +1917,9 @@ unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfS { nActualSpacing = 1; } - else if(nActualSpacing > Params().GetConsensus().nTargetTimespan) + else if(nActualSpacing > pnetMan->getActivePaymentNetwork()->GetConsensus().nTargetTimespan) { - nActualSpacing = Params().GetConsensus().nTargetTimespan; + nActualSpacing = pnetMan->getActivePaymentNetwork()->GetConsensus().nTargetTimespan; } // ppcoin: target change every block @@ -3179,14 +1929,14 @@ unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfS int64_t spacing; if (fProofOfStake) { - spacing = Params().GetConsensus().nTargetSpacing; + spacing = pnetMan->getActivePaymentNetwork()->GetConsensus().nTargetSpacing; } else { - spacing = std::min( (3 * (int64_t) Params().GetConsensus().nTargetSpacing), ((int64_t) Params().GetConsensus().nTargetSpacing * (1 + pindexLast->nHeight - pindexPrev->nHeight)) ); + spacing = std::min( (3 * (int64_t) pnetMan->getActivePaymentNetwork()->GetConsensus().nTargetSpacing), ((int64_t) pnetMan->getActivePaymentNetwork()->GetConsensus().nTargetSpacing * (1 + pindexLast->nHeight - pindexPrev->nHeight)) ); } int64_t nTargetSpacing = spacing; - int64_t nInterval = Params().GetConsensus().nTargetTimespan / nTargetSpacing; + int64_t nInterval = pnetMan->getActivePaymentNetwork()->GetConsensus().nTargetTimespan / nTargetSpacing; bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing); bnNew /= ((nInterval + 1) * nTargetSpacing); @@ -3239,7 +1989,7 @@ const int YEARLY_BLOCKCOUNT = 700800; int64_t GetProofOfStakeReward(int64_t nCoinAge, int nHeight) { int64_t nRewardCoinYear = 2.5 * MAX_MINT_PROOF_OF_STAKE; - int64_t CMS = chainActive.Tip()->nMoneySupply; + int64_t CMS = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nMoneySupply; if(CMS == (MAX_MONEY / 2)) { /// if we are already at max money supply limits (25 billion coins, we return 0 as no new coins are to be minted diff --git a/src/main.h b/src/main.h index 5b9d673f..57d04c7e 100644 --- a/src/main.h +++ b/src/main.h @@ -6,19 +6,16 @@ #ifndef BITCOIN_MAIN_H #define BITCOIN_MAIN_H -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #include "amount.h" -#include "chain.h" +#include "chain/chain.h" #include "coins.h" #include "net.h" #include "script/script_error.h" #include "sync.h" #include "versionbits.h" #include "uint256.h" -#include "utiltime.h" +#include "util/utiltime.h" +#include "undo.h" #include #include @@ -34,7 +31,7 @@ class CBlockIndex; class CBlockTreeDB; class CBloomFilter; -class CChainParams; +class CNetworkTemplate; class CInv; class CScriptCheck; class CTxMemPool; @@ -43,7 +40,8 @@ class CValidationState; struct CNodeStateStats; struct LockPoints; - +/** Default for returning change from tx back an address we already owned instead of a new one (try to select address with most value in it). */ +static const bool DEFAULT_RETURN_CHANGE = true; /** Default for accepting alerts from the P2P network. */ static const bool DEFAULT_ALERTS = false; /** Default for DEFAULT_WHITELISTRELAY. */ @@ -76,7 +74,7 @@ static const int MAX_SCRIPTCHECK_THREADS = 16; /** -par default (number of script-checking threads, 0 = auto) */ static const int DEFAULT_SCRIPTCHECK_THREADS = 0; /** Number of blocks that can be requested at any given time from a single peer. */ -static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16; +static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 64; /** Timeout in seconds during which a peer must stall block download progress before being disconnected. */ static const unsigned int BLOCK_STALLING_TIMEOUT = 2; /** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends @@ -124,16 +122,10 @@ static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8; static const int LAST_POW_BLOCK = 86400; -struct BlockHasher -{ - size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); } -}; - +extern CCriticalSection cs_LastBlockFile; extern CScript COINBASE_FLAGS; extern CCriticalSection cs_main; extern CTxMemPool mempool; -typedef boost::unordered_map BlockMap; -extern BlockMap mapBlockIndex; extern uint64_t nLastBlockTx; extern uint64_t nLastBlockSize; extern const std::string strMessageMagic; @@ -269,18 +261,14 @@ void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age); extern std::set setDirtyBlockIndex; extern ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS]; void PruneBlockIndexCandidates(); -bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams, const uint256& hash); +bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CNetworkTemplate& chainparams, const uint256& hash); bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams); -CBlockIndex* AddToBlockIndex(const CBlockHeader& block); - -/** Best header we've seen so far (used for getheaders queries' starting points). */ -extern CBlockIndex *pindexBestHeader; /** Minimum disk space required - used in CheckDiskSpace() */ static const uint64_t nMinDiskSpace = 52428800; /** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */ -static const unsigned int MIN_BLOCKS_TO_KEEP = 288; +static const unsigned int MIN_BLOCKS_TO_KEEP = 50; static const signed int DEFAULT_CHECKBLOCKS = MIN_BLOCKS_TO_KEEP; static const unsigned int DEFAULT_CHECKLEVEL = 3; @@ -297,11 +285,6 @@ static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024; static const int64_t MAX_MINT_PROOF_OF_STAKE = 0.1 * COIN; -/** Register with a network node to receive its signals */ -void RegisterNodeSignals(CNodeSignals& nodeSignals); -/** Unregister a network node */ -void UnregisterNodeSignals(CNodeSignals& nodeSignals); - const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake); unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake); int64_t GetProofOfWorkReward(int64_t nFees, const int nHeight, uint256 prevHash); @@ -327,28 +310,10 @@ FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false); FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false); /** Translation to a filesystem path */ boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix); -/** Import blocks from an external file */ -bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp = NULL); -/** Initialize a new block tree database + block data on disk */ -bool InitBlockIndex(const CChainParams& chainparams); -/** Load the block tree and coins database from disk */ -bool LoadBlockIndex(); -/** Unload database information */ -void UnloadBlockIndex(); -/** Process protocol messages received from a given node */ -bool ProcessMessages(CNode* pfrom); -/** - * Send queued protocol messages to be sent to a give node. - * - * @param[in] pto The node which we are sending messages to. - */ -bool SendMessages(CNode* pto); -/** Run an instance of the script checking thread */ -void ThreadScriptCheck(); + /** Try to detect Partition (network isolation) attacks against us */ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nTargetSpacing); -/** Check whether we are doing an initial block download (synchronizing from disk or network) */ -bool IsInitialBlockDownload(); + /** Format a string that describes several potential problems detected by the core. * strFor can have three values: * - "rpc": get critical warnings, which should put the client in safe mode if non-empty @@ -357,10 +322,9 @@ bool IsInitialBlockDownload(); * This function only returns the highest priority warning of the set selected by strFor. */ std::string GetWarnings(const std::string& strFor); -/** Retrieve a transaction (from memory pool, or from disk, if possible) */ -bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false); + /** Find the best known block, and make it the tip of the block chain */ -bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, BlockOrigin origin, const CBlock* pblock = NULL); +bool ActivateBestChain(CValidationState& state, const CNetworkTemplate& chainparams, BlockOrigin origin, const CBlock* pblock = NULL); enum FlushStateMode { FLUSH_STATE_NONE, @@ -373,41 +337,15 @@ extern int nPreferredDownload; extern int nSyncStarted; extern int64_t nTimeBestReceived; extern int nPeersWithValidatedDownloads; -extern boost::scoped_ptr recentRejects; - - -/** - * Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target. - * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new - * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex - * (which in this case means the blockchain must be re-downloaded.) - * - * Pruning functions are called from FlushStateToDisk when the global fCheckForPruning flag has been set. - * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.) - * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 1000 on regtest). - * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip. - * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files. - * A db flag records the fact that at least some block files have been pruned. - * - * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned - */ -void FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfterHeight); -/** - * Actually unlink the specified files - */ -void UnlinkPrunedFiles(std::set& setFilesToPrune); - -/** Create a new block index entry for a given block hash */ -CBlockIndex * InsertBlockIndex(uint256 hash); /** Get statistics from node state */ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats); + /** Increase a node's misbehavior score. */ void Misbehaving(NodeId nodeid, int howmuch); + /** Flush all state, indexes and buffers to disk. */ void FlushStateToDisk(); -/** Prune block files and flush state to disk. */ -void PruneAndFlush(); CNodeState *State(NodeId pnode); bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage=""); @@ -437,7 +375,7 @@ struct CDiskTxPos : public CDiskBlockPos ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(*(CDiskBlockPos*)this); READWRITE(VARINT(nTxOffset)); } @@ -483,9 +421,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi /** Apply the effects of this transaction on the UTXO set represented by view */ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight); - -/** Context-independent validity checks */ -bool CheckTransaction(const CTransaction& tx, CValidationState& state); +void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight); /** * Check if transaction is final and can be included in a block with the @@ -568,22 +504,12 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus /** Functions for validating blocks and updating the block tree */ -/** Undo the effects of this block (with given index) on the UTXO set represented by coins. - * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean - * will be true if no problems were found. Otherwise, the return value will be false in case - * of problems. Note that in any case, coins may be modified. */ -bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL); - -/** Apply the effects of this block (with given index) on the UTXO set represented by coins */ -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); - /** Context-independent validity checks */ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); /** Context-dependent validity checks */ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); -bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp); extern std::set setBlockIndexCandidates; class CBlockFileInfo @@ -600,7 +526,7 @@ class CBlockFileInfo ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(VARINT(nBlocks)); READWRITE(VARINT(nSize)); READWRITE(VARINT(nUndoSize)); @@ -640,32 +566,12 @@ class CBlockFileInfo } }; -/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */ -class CVerifyDB { -public: - CVerifyDB(); - ~CVerifyDB(); - bool VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth); -}; - -/** Find the last common block between the parameter chain and a locator. */ -CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator); - /** Mark a block as invalid. */ bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex *pindex); /** Remove invalidity status from a block and its descendants. */ bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex); -/** The currently-connected chain of blocks (protected by cs_main). */ -extern CChain chainActive; - -/** Global variable that points to the active CCoinsView (protected by cs_main) */ -extern CCoinsViewCache *pcoinsTip; - -/** Global variable that points to the active block tree (protected by cs_main) */ -extern CBlockTreeDB *pblocktree; - /** * Return the spend height, which is one more than the inputs.GetBestBlock(). * While checking, GetBestBlock() refers to the parent block. (protected by cs_main) @@ -690,4 +596,19 @@ static const unsigned int REJECT_ALREADY_KNOWN = 0x101; /** Transaction conflicts with a transaction already known */ static const unsigned int REJECT_CONFLICT = 0x102; +extern std::map mapNodeState; +extern int nLastBlockFile; +extern std::vector vinfoBlockFile; +bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos); +bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false); +bool AbortNode(const std::string& strMessage, const std::string& userMessage=""); +extern uint32_t nBlockSequenceId; +extern std::set setDirtyFileInfo; +/// versionbitscache was originally static in main.cpp might need to revert the change to non static +extern VersionBitsCache versionbitscache; + +extern int GetHeight(); +extern void InitializeNode(NodeId nodeid, const CNode *pnode); +extern void FinalizeNode(NodeId nodeid); + #endif // BITCOIN_MAIN_H diff --git a/src/makefile.bsd b/src/makefile.bsd deleted file mode 100644 index 9e17c7ab..00000000 --- a/src/makefile.bsd +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright (c) 2009-2010 Satoshi Nakamoto -# Distributed under the MIT/X11 software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -USE_UPNP:=0 -USE_IPV6:=1 - -LINK:=$(CXX) - -DEFS=-DBOOST_SPIRIT_THREADSAFE - -DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH)) -LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH)) - -LMODE = dynamic -LMODE2 = dynamic -ifdef STATIC - LMODE = static - ifeq (${STATIC}, all) - LMODE2 = static - endif -endif - -# for boost 1.37, add -mt to the boost libraries -LIBS += \ - -Wl,-B$(LMODE) \ - -l boost_system$(BOOST_LIB_SUFFIX) \ - -l boost_filesystem$(BOOST_LIB_SUFFIX) \ - -l boost_program_options$(BOOST_LIB_SUFFIX) \ - -l boost_thread$(BOOST_LIB_SUFFIX) \ - -l db_cxx$(BDB_LIB_SUFFIX) \ - -l ssl \ - -l crypto \ - -l execinfo - -ifndef USE_UPNP - override USE_UPNP = - -endif -ifneq (${USE_UPNP}, -) - LIBS += -l miniupnpc - DEFS += -DUSE_UPNP=$(USE_UPNP) -endif - -ifneq (${USE_IPV6}, -) - DEFS += -DUSE_IPV6=$(USE_IPV6) -endif - -LIBS+= \ - -Wl,-B$(LMODE2) \ - -l z \ - -l dl \ - -l pthread - - -# Hardening -# Make some classes of vulnerabilities unexploitable in case one is discovered. -# - # This is a workaround for Ubuntu bug #691722, the default -fstack-protector causes - # -fstack-protector-all to be ignored unless -fno-stack-protector is used first. - # see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722 - HARDENING=-fno-stack-protector - - # Stack Canaries - # Put numbers at the beginning of each stack frame and check that they are the same. - # If a stack buffer if overflowed, it writes over the canary number and then on return - # when that number is checked, it won't be the same and the program will exit with - # a "Stack smashing detected" error instead of being exploited. - HARDENING+=-fstack-protector-all -Wstack-protector - - # Make some important things such as the global offset table read only as soon as - # the dynamic linker is finished building it. This will prevent overwriting of addresses - # which would later be jumped to. - LDHARDENING+=-Wl,-z,relro -Wl,-z,now - - # Build position independent code to take advantage of Address Space Layout Randomization - # offered by some kernels. - # see doc/build-unix.txt for more information. - ifdef PIE - HARDENING+=-fPIE - LDHARDENING+=-pie - endif - - # -D_FORTIFY_SOURCE=2 does some checking for potentially exploitable code patterns in - # the source such overflowing a statically defined buffer. - HARDENING+=-D_FORTIFY_SOURCE=2 -# - - -DEBUGFLAGS=-g - -# CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only -# adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work. -xCXXFLAGS=-O0 -msse2 -pthread -Wall -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter -std=c++11 \ - $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS) - -# LDFLAGS can be specified on the make command line, so we use xLDFLAGS that only -# adds some defaults in front. Unfortunately, LDFLAGS=... $(LDFLAGS) does not work. -xLDFLAGS=$(LDHARDENING) $(LDFLAGS) - -OBJS= \ - build/version.o \ - build/checkpoints.o \ - build/network/netaddr.o \ - build/network/addrman.o \ - build/crypter.o \ - build/key.o \ - build/db.o \ - build/init.o \ - build/keystore.o \ - build/miner.o \ - build/main.o \ - build/net.o \ - build/network/protocol.o \ - build/bitcoinrpc.o \ - build/rpcdump.o \ - build/rpcnet.o \ - build/rpcmining.o \ - build/rpcwallet.o \ - build/rpcblockchain.o \ - build/rpcrawtransaction.o \ - build/script.o \ - build/sync.o \ - build/util/util.o \ - build/wallet.o \ - build/walletdb.o \ - build/noui.o \ - build/kernel.o \ - build/pbkdf2.o \ - build/messages.o \ - build/block.o \ - build/global.o \ - build/points.o \ - build/chain.o \ - build/blockindex.o \ - build/hash.o \ - build/locator.o \ - build/transaction.o \ - build/merkle_transaction.o \ - build/mempool.o \ - build/scrypt.o \ - build/network/netutils.o \ - build/network/node.o \ - build/network/proxyutils.o \ - build/network/requests.o \ - build/network/service.o \ - build/network/socketutils.o \ - build/util/utilexceptions.o \ - build/util/utilmoneystr.o \ - build/util/utilstrencodings.o \ - build/util/utiltime.o \ - build/univalue.o \ - build/univalue_write.o \ - build/univalue_read.o \ - build/random.o \ - build/server.o \ - build/fs.o - -all: MultiWalletCoind - -LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a -DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) -DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) -OBJS += obj/txdb-leveldb.o -leveldb/libleveldb.a: - @echo "Building LevelDB ..."; cd leveldb; make libleveldb.a libmemenv.a; cd ..; -obj/txdb-leveldb.o: leveldb/libleveldb.a - -# auto-generated dependencies: --include obj/*.P - -obj/build.h: FORCE - /bin/sh ../share/genbuild.sh obj/build.h -version.cpp: obj/build.h -DEFS += -DHAVE_BUILD_INFO - -obj/scrypt-x86.o: scrypt-x86.S - $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< - -obj/scrypt-x86_64.o: scrypt-x86_64.S - $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< - -obj/scrypt-arm.o: scrypt-arm.S - $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< - -obj/%.o: %.cpp - $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< - @cp $(@:%.o=%.d) $(@:%.o=%.P); \ - sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ - -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ - rm -f $(@:%.o=%.d) - -obj/zerocoin/%.o: zerocoin/%.cpp - $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< - @cp $(@:%.o=%.d) $(@:%.o=%.P); \ - sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ - -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ - rm -f $(@:%.o=%.d) - -MultiWalletCoind: $(OBJS:obj/%=obj/%) - $(LINK) $(xCXXFLAGS) -o $@ $^ $(xLDFLAGS) $(LIBS) - -clean: - -rm -f MultiWalletCoind - -rm -f obj/*.o - -rm -f obj/zerocoin/*.o - -rm -f obj/*.P - -rm -f obj/zerocoin/*.P - -rm -f obj/build.h - -FORCE: diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw deleted file mode 100644 index 304c5e38..00000000 --- a/src/makefile.linux-mingw +++ /dev/null @@ -1,160 +0,0 @@ -# Copyright (c) 2009-2010 Satoshi Nakamoto -# Distributed under the MIT/X11 software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -TARGET_PLATFORM:=i686 -#TARGET_PLATFORM:=x86_64 - -DEPSDIR:=/usr/$(TARGET_PLATFORM)-w64-mingw32 -CC:=$(TARGET_PLATFORM)-w64-mingw32-gcc -CXX:=$(TARGET_PLATFORM)-w64-mingw32-g++ -RANLIB=$(TARGET_PLATFORM)-w64-mingw32-ranlib -STRIP=$(TARGET_PLATFORM)-w64-mingw32-strip - -USE_UPNP:=0 -USE_IPV6:=1 - -INCLUDEPATHS= \ - -I"$(CURDIR)" \ - -I"$(CURDIR)"/obj \ - -I"$(DEPSDIR)/boost_1_55_0" \ - -I"$(DEPSDIR)/db-6.0.20/build_unix" \ - -I"$(DEPSDIR)/openssl-1.0.1f/include" \ - -I"$(DEPSDIR)" - -LIBPATHS= \ - -L"$(DEPSDIR)/boost_1_55_0/stage/lib" \ - -L"$(DEPSDIR)/db-6.0.20/build_unix" \ - -L"$(DEPSDIR)/openssl-1.0.1f" - -LIBS= \ - -l boost_system-mt \ - -l boost_filesystem-mt \ - -l boost_program_options-mt \ - -l boost_thread_win32-mt \ - -l boost_chrono-mt \ - -l db_cxx \ - -l ssl \ - -l crypto - -DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -DEBUGFLAGS=-g -CFLAGS=-O3 -msse2 -w -Wall -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter -std=c++11 $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) -LDFLAGS=-Wl,--dynamicbase -Wl,--nxcompat -static-libgcc -static-libstdc++ - -ifndef USE_UPNP - override USE_UPNP = - -endif -ifneq (${USE_UPNP}, -) - LIBPATHS += -L"$(DEPSDIR)/miniupnpc" - LIBS += -l miniupnpc -l iphlpapi - DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP) -endif - -ifneq (${USE_IPV6}, -) - DEFS += -DUSE_IPV6=$(USE_IPV6) -endif - -LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi - -# TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are -HEADERS = $(wildcard *.h) - -OBJS= \ - build/version.o \ - build/checkpoints.o \ - build/network/netaddr.o \ - build/network/addrman.o \ - build/crypter.o \ - build/key.o \ - build/db.o \ - build/init.o \ - build/keystore.o \ - build/miner.o \ - build/main.o \ - build/net.o \ - build/network/protocol.o \ - build/bitcoinrpc.o \ - build/rpcdump.o \ - build/rpcnet.o \ - build/rpcmining.o \ - build/rpcwallet.o \ - build/rpcblockchain.o \ - build/rpcrawtransaction.o \ - build/script.o \ - build/sync.o \ - build/util/util.o \ - build/wallet.o \ - build/walletdb.o \ - build/noui.o \ - build/kernel.o \ - build/pbkdf2.o \ - build/messages.o \ - build/block.o \ - build/global.o \ - build/points.o \ - build/chain.o \ - build/blockindex.o \ - build/hash.o \ - build/locator.o \ - build/transaction.o \ - build/merkle_transaction.o \ - build/mempool.o \ - build/scrypt.o \ - build/network/netutils.o \ - build/network/node.o \ - build/network/proxyutils.o \ - build/network/requests.o \ - build/network/service.o \ - build/network/socketutils.o \ - build/util/utilexceptions.o \ - build/util/utilmoneystr.o \ - build/util/utilstrencodings.o \ - build/util/utiltime.o \ - build/univalue.o \ - build/univalue_write.o \ - build/univalue_read.o \ - build/random.o \ - build/server.o \ - build/fs.o - - -all: MultiWalletCoind.exe - -LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a -DEFS += -I"$(CURDIR)/leveldb/include" -DEFS += -I"$(CURDIR)/leveldb/helpers" -OBJS += obj/txdb-leveldb.o -leveldb/libleveldb.a: - @echo "Building LevelDB ..." && cd leveldb && CC=$(CC) CXX=$(CXX) TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$(INCLUDEPATHS)" LDFLAGS="-L$(LIBPATHS)" $(MAKE) libleveldb.a libmemenv.a && $(RANLIB) libleveldb.a && $(RANLIB) libmemenv.a && cd .. -obj/txdb-leveldb.o: leveldb/libleveldb.a - -obj/build.h: FORCE - /bin/sh ../share/genbuild.sh obj/build.h -version.cpp: obj/build.h -DEFS += -DHAVE_BUILD_INFO - -obj/%.o: %.cpp $(HEADERS) - $(CXX) -c $(CFLAGS) -o $@ $< - -obj/zerocoin/%.o: zerocoin/%.cpp $(HEADERS) - $(CXX) -c $(CFLAGS) -o $@ $< - -MultiWalletCoind.exe: $(OBJS:obj/%=obj/%) - $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) -lshlwapi - $(STRIP) MultiWalletCoind.exe - -obj/scrypt-x86.o: scrypt-x86.S - $(CXX) -c $(CFLAGS) -MMD -o $@ $< - -obj/scrypt-x86_64.o: scrypt-x86_64.S - $(CXX) -c $(CFLAGS) -MMD -o $@ $< - -clean: - -rm -f obj/*.o - -rm -f obj/zerocoin/*.o - -rm -f MultiWalletCoind.exe - -rm -f obj/build.h - cd leveldb && TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) clean && cd .. - -FORCE: diff --git a/src/makefile.mingw b/src/makefile.mingw deleted file mode 100644 index 29827826..00000000 --- a/src/makefile.mingw +++ /dev/null @@ -1,183 +0,0 @@ -# Copyright (c) 2009-2010 Satoshi Nakamoto -# Distributed under the MIT/X11 software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -# Makefile for the MinGW g++ compiler/toolchain -# -# Assumes Berkeley DB, Boost, and OpenSSL have all been compiled and installed -# into /usr/local (/usr/local/include, /usr/local/lib). -# -# If dependencies are somewhere else, run 'make DEPSDIR=/path/' -# -# Boost libraries are given wacky names that include the particular version of -# boost you're using; set BOOST_SUFFIX appropriately. -# -# 'make clean' assumes it is running inside a MSYS shell, and uses 'rm' -# to remove files. - -CXX ?= g++ - -USE_UPNP:=- -USE_IPV6:=1 - -DEPSDIR?=/usr/local -BOOST_SUFFIX?=-mgw48-mt-s-1_55 - -INCLUDEPATHS= \ - -I"$(CURDIR)" \ - -I"$(DEPSDIR)/include" \ - -I"c:/deps/boost_1_55_0" \ - -I"c:/deps/db-4.8.30.NC/build_unix" \ - -I"c:/deps/miniupnpc-1.8" \ - -I"c:/deps/openssl-1.0.1g/include" - -LIBPATHS= \ - -L"$(CURDIR)/leveldb" \ - -L"$(DEPSDIR)/lib" \ - -L"c:/deps/boost_1_55_0/stage/lib" \ - -L"c:/deps/db-4.8.30.NC/build_unix" \ - -L"c:/deps/miniupnpc-1.8" \ - -L"c:/deps/openssl-1.0.1g" - -LIBS= \ - -l leveldb \ - -l memenv \ - -l boost_system$(BOOST_SUFFIX) \ - -l boost_filesystem$(BOOST_SUFFIX) \ - -l boost_program_options$(BOOST_SUFFIX) \ - -l boost_thread$(BOOST_SUFFIX) \ - -l boost_chrono$(BOOST_SUFFIX) \ - -l db_cxx \ - -l ssl \ - -l crypto - -DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -DEBUGFLAGS=-g -CFLAGS=-mthreads -O3 -msse2 -w -Wall -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter -std=c++11 $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) -LDFLAGS=-Wl,--dynamicbase -Wl,--nxcompat - -TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data) - -ifndef USE_UPNP - override USE_UPNP = - -endif -ifneq (${USE_UPNP}, -) - INCLUDEPATHS += -I"C:\miniupnpc-1.6" - LIBPATHS += -L"C:\miniupnpc-1.6" - LIBS += -l miniupnpc -l iphlpapi - DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP) -endif - -ifneq (${USE_IPV6}, -) - DEFS += -DUSE_IPV6=$(USE_IPV6) -endif - -LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi - -# TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are -HEADERS = $(wildcard *.h) - -OBJS= \ - build/version.o \ - build/checkpoints.o \ - build/network/netaddr.o \ - build/network/addrman.o \ - build/crypter.o \ - build/key.o \ - build/db.o \ - build/init.o \ - build/keystore.o \ - build/miner.o \ - build/main.o \ - build/net.o \ - build/network/protocol.o \ - build/bitcoinrpc.o \ - build/rpcdump.o \ - build/rpcnet.o \ - build/rpcmining.o \ - build/rpcwallet.o \ - build/rpcblockchain.o \ - build/rpcrawtransaction.o \ - build/script.o \ - build/sync.o \ - build/util/util.o \ - build/wallet.o \ - build/walletdb.o \ - build/noui.o \ - build/kernel.o \ - build/pbkdf2.o \ - build/messages.o \ - build/block.o \ - build/global.o \ - build/points.o \ - build/chain.o \ - build/blockindex.o \ - build/hash.o \ - build/locator.o \ - build/transaction.o \ - build/merkle_transaction.o \ - build/mempool.o \ - build/scrypt.o \ - build/network/netutils.o \ - build/network/node.o \ - build/network/proxyutils.o \ - build/network/requests.o \ - build/network/service.o \ - build/network/socketutils.o \ - build/util/utilexceptions.o \ - build/util/utilmoneystr.o \ - build/util/utilstrencodings.o \ - build/util/utiltime.o \ - build/univalue.o \ - build/univalue_write.o \ - build/univalue_read.o \ - build/random.o \ - build/server.o \ - build/fs.o - - -all: MultiWalletCoind.exe - -LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a -DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) -DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) -OBJS += obj/txdb-leveldb.o -leveldb/libleveldb.a: - cd leveldb; make; cd .. -obj/txdb-leveldb.o: leveldb/libleveldb.a - -obj/%.o: %.cpp $(HEADERS) - g++ -c $(CFLAGS) -o $@ $< - - -obj/scrypt-x86.o: scrypt-x86.S - $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< - -obj/scrypt-x86_64.o: scrypt-x86_64.S - $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< - -obj/scrypt-arm.o: scrypt-arm.S - $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< - -obj/%.o: %.c - $(CXX) -c $(xCXXFLAGS) -fpermissive -MMD -MF $(@:%.o=%.d) -o $@ $< - @cp $(@:%.o=%.d) $(@:%.o=%.P); \ - sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ - -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ - - rm -f $(@:%.o=%.d) -obj/%.o: %.cpp - $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< - @cp $(@:%.o=%.d) $(@:%.o=%.P); \ - sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ - -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ - rm -f $(@:%.o=%.d) - -MultiWalletCoind.exe: $(OBJS:obj/%=obj/%) - g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) - -clean: - -del /Q MultiWalletCoind - -del /Q obj\* - -FORCE: diff --git a/src/makefile.osx b/src/makefile.osx deleted file mode 100644 index 6c09bdb3..00000000 --- a/src/makefile.osx +++ /dev/null @@ -1,234 +0,0 @@ -# -*- mode: Makefile; -*- -# Copyright (c) 2011 Bitcoin Developers -# Distributed under the MIT/X11 software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -# Mac OS X makefile for MultiWalletCoin -# Originally by Laszlo Hanyecz (solar@heliacal.net) - -CXX=llvm-g++ -DEPSDIR=/usr/local - -INCLUDEPATHS= \ - -I"$(CURDIR)" \ - -I"$(CURDIR)"/build \ - -I"$(DEPSDIR)/include" \ - -I"$(DEPSDIR)/include/db48" - -LIBPATHS= \ - -L"$(DEPSDIR)/lib" \ - -L"$(DEPSDIR)/lib/db48" - -USE_UPNP:=1 -USE_IPV6:=1 - -LIBS= -dead_strip - -ifdef STATIC -# Build STATIC if you are redistributing the ECCoind binary -LIBS += \ - $(DEPSDIR)/lib/db48/libdb_cxx-4.8.a \ - $(DEPSDIR)/lib/libboost_system-mt.a \ - $(DEPSDIR)/lib/libboost_filesystem-mt.a \ - $(DEPSDIR)/lib/libboost_program_options-mt.a \ - $(DEPSDIR)/lib/libboost_thread-mt.a \ - $(DEPSDIR)/lib/libssl.a \ - $(DEPSDIR)/lib/libcrypto.a \ - -lz -else -LIBS += \ - -ldb_cxx-4.8 \ - -lboost_system-mt \ - -lboost_filesystem-mt \ - -lboost_program_options-mt \ - -lboost_thread-mt \ - -lssl \ - -lcrypto \ - -lz -endif - -DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DBOOST_SPIRIT_THREADSAFE - -ifdef RELEASE -# Compile for maximum compatibility and smallest size. -# This requires that dependencies are compiled -# the same way. -CFLAGS = -mmacosx-version-min=10.5 -arch x86_64 -O3 -msse2 -else -CFLAGS = -g -msse2 -endif - -# ppc doesn't work because we don't support big-endian -CFLAGS += -Wall -Wextra -Wformat -Wno-ignored-qualifiers -Wformat-security -Wno-unused-parameter -stdlib=libc++ -std=c++11\ - $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) - -OBJS= \ - build/txdb.o \ - build/key.o \ - build/addrman.o \ - build/amount.o \ - build/arith_uint256.o \ - build/base58.o \ - build/bloom.o \ - build/chain.o \ - build/chainparams.o \ - build/chainparamsbase.o \ - build/checkpoints.o \ - build/clientversion.o \ - build/coins.o \ - build/compressor.o \ - build/core_read.o \ - build/core_write.o \ - build/dbwrapper.o \ - build/hash.o \ - build/keystore.o \ - build/main.o \ - build/merkleblock.o \ - build/miner.o \ - build/net.o \ - build/netbase.o \ - build/noui.o \ - build/pow.o \ - build/protocol.o \ - build/pubkey.o \ - build/random.o \ - build/scheduler.o \ - build/sync.o \ - build/timedata.o \ - build/torcontrol.o \ - build/txmempool.o \ - build/uint256.o \ - build/util.o \ - build/fs.o \ - build/args.o \ - build/utilmoneystr.o \ - build/utilstrencodings.o \ - build/utiltime.o \ - build/validationinterface.o \ - build/versionbits.o \ - build/wallet/crypter.o \ - build/wallet/db.o \ - build/wallet/wallet.o \ - build/wallet/wallet_ismine.o \ - build/wallet/walletdb.o \ - build/support/cleanse.o \ - build/support/pagelocker.o \ - build/script/bitcoinconsensus.o \ - build/script/interpreter.o \ - build/script/script.o \ - build/script/script_error.o \ - build/script/sigcache.o \ - build/script/sign.o \ - build/script/standard.o \ - build/primitives/block.o \ - build/primitives/transaction.o \ - build/policy/fees.o \ - build/policy/policy.o \ - build/policy/rbf.o \ - build/crypto/hmac_sha256.o \ - build/crypto/hmac_sha512.o \ - build/crypto/ripemd160.o \ - build/crypto/sha1.o \ - build/crypto/sha256.o \ - build/crypto/sha512.o \ - build/consensus/merkle.o \ - build/compat/glibc_compat.o \ - build/compat/glibc_sanity.o \ - build/compat/glibcxx_sanity.o \ - build/compat/strnlen.o \ - build/init.o \ - build/bitcoind.o \ - build/crypto/scrypt.o \ - build/kernel.o \ - build/httprpc.o \ - build/httpserver.o \ - build/rest.o \ - build/rpcblockchain.o \ - build/rpcclient.o \ - build/rpcmining.o \ - build/rpcmisc.o \ - build/rpcnet.o \ - build/rpcprotocol.o \ - build/rpcrawtransaction.o \ - build/rpcserver.o \ - build/univalue/univalue.o \ - build/univalue/univalue_read.o \ - build/univalue/univalue_write.o \ - build/pbkdf2.o \ - build/script/stakescript.o - - - -ifndef USE_UPNP - override USE_UPNP = - -endif -ifneq (${USE_UPNP}, -) - DEFS += -DUSE_UPNP=$(USE_UPNP) -ifdef STATIC - LIBS += $(DEPSDIR)/lib/libminiupnpc.a -else - LIBS += -lminiupnpc -endif -endif - -ifneq (${USE_IPV6}, -) - DEFS += -DUSE_IPV6=$(USE_IPV6) -endif - -all: leveldb secp256k1 ECCoind - -LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a -DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) -DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) -OBJS += build/txdb-leveldb.o - -leveldb_make: - cd leveldb; make; cd ..; -leveldb: leveldb_make - -DEFS += $(addprefix -I,$(CURDIR)/secp256k1/include) -LIBS += $(CURDIR)/secp256k1/lib/libsecp256k1.a - -secp256k1_make: - cd secp256k1; ./autogen.sh; ./configure --prefix=$(CURDIR)/libsecp256k1 --enable-module-recovery; make; make install; cd ..; -secp256k1: secp256k1_make - -# auto-generated dependencies: --include build/*.P - -build/build.h: FORCE - /bin/sh ../share/genbuild.sh build/build.h -version.cpp: build/build.h -DEFS += -DHAVE_BUILD_INFO - -build/%.o: %.cpp - $(CXX) -c $(CFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< - @cp $(@:%.o=%.d) $(@:%.o=%.P); \ - sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ - -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ - rm -f $(@:%.o=%.d) - -build/scrypt-x86.o: scrypt-x86.S - $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< - -build/scrypt-x86_64.o: scrypt-x86_64.S - $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< - -ECCoind: $(OBJS:build/%=build/%) - $(CXX) $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) - -clean: - -rm -f ECCoind - -rm -f build/*.o - -rm -f build/*.P - -rm -f build/build.h - -rm -f build/network/*.o - -rm -f build/netowkr/*.P - -rm -f build/util/*.o - -rm -f build/util/*.P - -rm -f build/rpc/*.o - -rm -f build/rpc/*.P - -rm -f build/crypto/*.o - -rm -f builf/crypto*.P - -FORCE: diff --git a/src/makefile.unix b/src/makefile.unix index c62d51d7..8e9816ee 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -1,4 +1,5 @@ -# Copyright (c) 2009-2010 Satoshi Nakamoto +# Copyright (c) 2009-2014 Satoshi Nakamoto +# Copyright (c) 2014-2017 Greg Griffith # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -100,7 +101,7 @@ endif # CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only # adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work. -xCXXFLAGS=-O2 $(EXT_OPTIONS) -pthread -w -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter -std=c++11 -DBOOST_NO_CXX11_SCOPED_ENUMS -fpermissive \ +xCXXFLAGS=-O2 $(EXT_OPTIONS) -pthread -w -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter -std=c++11 -DBOOST_NO_CXX11_SCOPED_ENUMS \ $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS) # LDFLAGS can be specified on the make command line, so we use xLDFLAGS that only @@ -124,19 +125,19 @@ OBJS= \ build/amount.o \ build/arith_uint256.o \ build/base58.o \ - build/blockindex.o \ + build/chain/blockindex.o \ build/bloom.o \ - build/chain.o \ - build/chainparams.o \ - build/chainparamsbase.o \ - build/checkpoints.o \ + build/chain/chain.o \ + build/chain/chainman.o \ + build/networks/netman.o \ + build/chain/checkpoints.o \ build/clientversion.o \ build/coins.o \ build/compressor.o \ build/core_read.o \ build/core_write.o \ build/dbwrapper.o \ - build/hash.o \ + build/crypto/hash.o \ build/keystore.o \ build/main.o \ build/merkleblock.o \ @@ -157,12 +158,12 @@ OBJS= \ build/torcontrol.o \ build/txmempool.o \ build/uint256.o \ - build/util.o \ + build/util/util.o \ build/fs.o \ build/args.o \ - build/utilmoneystr.o \ - build/utilstrencodings.o \ - build/utiltime.o \ + build/util/utilmoneystr.o \ + build/util/utilstrencodings.o \ + build/util/utiltime.o \ build/validationinterface.o \ build/versionbits.o \ build/wallet/crypter.o \ @@ -179,8 +180,8 @@ OBJS= \ build/script/sigcache.o \ build/script/sign.o \ build/script/standard.o \ - build/primitives/block.o \ - build/primitives/transaction.o \ + build/chain/block.o \ + build/tx/tx.o \ build/policy/fees.o \ build/policy/policy.o \ build/policy/rbf.o \ @@ -190,33 +191,39 @@ OBJS= \ build/crypto/sha1.o \ build/crypto/sha256.o \ build/crypto/sha512.o \ + build/crypto/chacha20.o \ build/consensus/merkle.o \ build/compat/glibc_compat.o \ build/compat/glibc_sanity.o \ build/compat/glibcxx_sanity.o \ build/compat/strnlen.o \ build/init.o \ - build/bitcoind.o \ + build/eccoind.o \ build/crypto/scrypt.o \ build/kernel.o \ build/httprpc.o \ build/httpserver.o \ build/rest.o \ - build/rpcblockchain.o \ - build/rpcclient.o \ - build/rpcdump.o \ - build/rpcmining.o \ - build/rpcmisc.o \ - build/rpcnet.o \ - build/rpcprotocol.o \ - build/rpcrawtransaction.o \ - build/rpcserver.o \ - build/rpcwallet.o \ + build/rpc/rpcblockchain.o \ + build/rpc/rpcclient.o \ + build/rpc/rpcdump.o \ + build/rpc/rpcmining.o \ + build/rpc/rpcmisc.o \ + build/rpc/rpcnet.o \ + build/rpc/rpcprotocol.o \ + build/rpc/rpcrawtransaction.o \ + build/rpc/rpcserver.o \ + build/rpc/rpcwallet.o \ build/univalue/univalue.o \ build/univalue/univalue_read.o \ build/univalue/univalue_write.o \ build/pbkdf2.o \ - build/script/stakescript.o + build/script/stakescript.o \ + build/signals.o \ + build/processtx.o \ + build/verifydb.o + + all: leveldb secp256k1 ECCoind @@ -240,17 +247,11 @@ DEFS += -DHAVE_BUILD_INFO build/%.o: %.c - $(CXX) -c $(xCXXFLAGS) -fpermissive -MMD -MF $(@:%.o=%.d) -o $@ $< + $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< @cp $(@:%.o=%.d) $(@:%.o=%.P); \ sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ -build/scrypt-x86.o: scrypt-x86.S - $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< - -build/scrypt-x86_64.o: scrypt-x86_64.S - $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< - rm -f $(@:%.o=%.d) build/%.o: %.cpp $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< diff --git a/src/makefile.xosx b/src/makefile.xosx deleted file mode 100644 index a6a5e805..00000000 --- a/src/makefile.xosx +++ /dev/null @@ -1,290 +0,0 @@ -# Copyright (c) 2009-2010 Satoshi Nakamoto -# Distributed under the MIT/X11 software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -USE_UPNP:=1 -USE_IPV6:=1 - - -LINK:=$(CXX) -ARCH:=$(system lscpu | head -n 1 | awk '{print $2}') - -DEFS=-DBOOST_SPIRIT_THREADSAFE - -DEFS += $(addprefix -I,/home/parallels/Documents/osxcross/target/macports/pkgs/opt/local/include/openssl /home/parallels/Documents/osxcross/target/macports/pkgs/opt/local/include/db48 $(CURDIR) $(CURDIR)/build $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH) $(EVENT_INCLUDE_PATH) $(CURDIR)/univalue) -LIBS = $(addprefix -L,/home/parallels/Documents/osxcross/target/macports/pkgs/opt/local/lib/db48 $(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH) $(EVENT_LIB_PATH)) - -LMODE = dynamic -LMODE2 = dynamic -ifdef STATIC - LMODE = static - ifeq (${STATIC}, all) - LMODE2 = static - endif -endif - -# for boost 1.37, add -mt to the boost libraries -LIBS += \ - -Wl,-B$(LMODE) \ - -l boost_system$(BOOST_LIB_SUFFIX) \ - -l boost_filesystem$(BOOST_LIB_SUFFIX) \ - -l boost_program_options$(BOOST_LIB_SUFFIX) \ - -l boost_thread$(BOOST_LIB_SUFFIX) \ - -l boost_chrono$(BOOST_LIB_SUFFIX) \ - -l db_cxx$(BDB_LIB_SUFFIX) \ - -l ssl \ - -l event \ - -l event_pthreads \ - -l crypto - -ifndef USE_UPNP - override USE_UPNP = - -endif -ifneq (${USE_UPNP}, -) - LIBS += -l miniupnpc - DEFS += -DUSE_UPNP=$(USE_UPNP) -endif - -ifneq (${USE_IPV6}, -) - DEFS += -DUSE_IPV6=$(USE_IPV6) -endif - -LIBS+= \ - -Wl,-B$(LMODE2) \ - -l z \ - -l dl \ - -l pthread - - -# Hardening -# Make some classes of vulnerabilities unexploitable in case one is discovered. -# - # This is a workaround for Ubuntu bug #691722, the default -fstack-protector causes - # -fstack-protector-all to be ignored unless -fno-stack-protector is used first. - # see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722 - HARDENING=-fno-stack-protector - - # Stack Canaries - # Put numbers at the beginning of each stack frame and check that they are the same. - # If a stack buffer if overflowed, it writes over the canary number and then on return - # when that number is checked, it won't be the same and the program will exit with - # a "Stack smashing detected" error instead of being exploited. - HARDENING+=-fstack-protector-all -Wstack-protector - - # Make some important things such as the global offset table read only as soon as - # the dynamic linker is finished building it. This will prevent overwriting of addresses - # which would later be jumped to. - LDHARDENING+=-Wl,-z,relro -Wl,-z,now - - # Build position independent code to take advantage of Address Space Layout Randomization - # offered by some kernels. - # see doc/build-unix.txt for more information. - ifdef PIE - HARDENING+=-fPIE - LDHARDENING+=-pie - endif - - # -D_FORTIFY_SOURCE=2 does some checking for potentially exploitable code patterns in - # the source such overflowing a statically defined buffer. - HARDENING+=-D_FORTIFY_SOURCE=2 -# - - -DEBUGFLAGS=-g - - -ifeq (${ARCH}, i686) - EXT_OPTIONS=-msse2 -endif - - -# CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only -# adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work. -xCXXFLAGS=-O2 $(EXT_OPTIONS) -pthread -w -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter -std=c++11 -DBOOST_NO_CXX11_SCOPED_ENUMS -fpermissive \ - $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS) - -# LDFLAGS can be specified on the make command line, so we use xLDFLAGS that only -# adds some defaults in front. Unfortunately, LDFLAGS=... $(LDFLAGS) does not work. -xLDFLAGS=$(LDHARDENING) $(LDFLAGS) - -#add project specific libraries -LIBS += $(CURDIR)/leveldb/out-static/libleveldb.a $(CURDIR)/leveldb/out-static/libmemenv.a -LIBS += $(CURDIR)/secp256k1/.libs/libsecp256k1.a - -#add project specific dependencies -DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) -DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) -DEFS += $(addprefix -I,$(CURDIR)/secp256k1/include) - - -OBJS= \ - build/txdb.o \ - build/key.o \ - build/addrman.o \ - build/amount.o \ - build/arith_uint256.o \ - build/base58.o \ - build/blockindex.o \ - build/bloom.o \ - build/chain.o \ - build/chainparams.o \ - build/chainparamsbase.o \ - build/checkpoints.o \ - build/clientversion.o \ - build/coins.o \ - build/compressor.o \ - build/core_read.o \ - build/core_write.o \ - build/dbwrapper.o \ - build/hash.o \ - build/keystore.o \ - build/main.o \ - build/merkleblock.o \ - build/messages.o \ - build/miner.o \ - build/net.o \ - build/netbase.o \ - build/noui.o \ - build/pow.o \ - build/processblock.o \ - build/processheader.o \ - build/protocol.o \ - build/pubkey.o \ - build/random.o \ - build/scheduler.o \ - build/sync.o \ - build/timedata.o \ - build/torcontrol.o \ - build/txmempool.o \ - build/uint256.o \ - build/util.o \ - build/utilmoneystr.o \ - build/utilstrencodings.o \ - build/utiltime.o \ - build/validationinterface.o \ - build/versionbits.o \ - build/wallet/crypter.o \ - build/wallet/db.o \ - build/wallet/wallet.o \ - build/wallet/wallet_ismine.o \ - build/wallet/walletdb.o \ - build/support/cleanse.o \ - build/support/pagelocker.o \ - build/script/bitcoinconsensus.o \ - build/script/interpreter.o \ - build/script/script.o \ - build/script/script_error.o \ - build/script/sigcache.o \ - build/script/sign.o \ - build/script/standard.o \ - build/primitives/block.o \ - build/primitives/transaction.o \ - build/policy/fees.o \ - build/policy/policy.o \ - build/policy/rbf.o \ - build/crypto/hmac_sha256.o \ - build/crypto/hmac_sha512.o \ - build/crypto/ripemd160.o \ - build/crypto/sha1.o \ - build/crypto/sha256.o \ - build/crypto/sha512.o \ - build/consensus/merkle.o \ - build/compat/glibc_compat.o \ - build/compat/glibc_sanity.o \ - build/compat/glibcxx_sanity.o \ - build/compat/strnlen.o \ - build/init.o \ - build/bitcoind.o \ - build/crypto/scrypt.o \ - build/kernel.o \ - build/httprpc.o \ - build/httpserver.o \ - build/rest.o \ - build/rpcblockchain.o \ - build/rpcclient.o \ - build/rpcdump.o \ - build/rpcmining.o \ - build/rpcmisc.o \ - build/rpcnet.o \ - build/rpcprotocol.o \ - build/rpcrawtransaction.o \ - build/rpcserver.o \ - build/rpcwallet.o \ - build/univalue/univalue.o \ - build/univalue/univalue_read.o \ - build/univalue/univalue_write.o \ - build/pbkdf2.o \ - build/script/stakescript.o - -all: leveldb secp256k1 ECCoind - -leveldb_make: - cd leveldb; make; cd ..; -leveldb: leveldb_make - -secp256k1_make: - cd secp256k1; ./autogen.sh; ./configure --prefix=$(CURDIR)/libsecp256k1 --enable-module-recovery --with-bignum=no; make; make install; cd ..; -secp256k1: secp256k1_make - - - -# auto-generated dependencies: --include build/*.P - -build/build.h: FORCE - /bin/sh ../share/genbuild.sh build/build.h -clientversion.cpp: build/build.h -DEFS += -DHAVE_BUILD_INFO - - -build/%.o: %.c - $(CXX) -c $(xCXXFLAGS) -fpermissive -MMD -MF $(@:%.o=%.d) -o $@ $< - @cp $(@:%.o=%.d) $(@:%.o=%.P); \ - sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ - -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ - -build/scrypt-x86.o: scrypt-x86.S - $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< - -build/scrypt-x86_64.o: scrypt-x86_64.S - $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< - - rm -f $(@:%.o=%.d) -build/%.o: %.cpp - $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< - @cp $(@:%.o=%.d) $(@:%.o=%.P); \ - sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ - -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ - rm -f $(@:%.o=%.d) - -ECCoind: $(OBJS:build/%=build/%) - $(LINK) $(xCXXFLAGS) -o $@ $^ $(xLDFLAGS) $(LIBS) - -clean: - -rm -f ECCoind - -rm -f build/*.o - -rm -f build/*.P - -rm -f build/build.h - -rm -f build/compat/*.o - -rm -f build/compat/*.P - -rm -f build/consensus/*.o - -rm -f build/consensus/*.P - -rm -f build/crypto/*.o - -rm -f build/crypto/*.P - -rm -f build/policy/*.o - -rm -f build/policy/*.P - -rm -f build/primitives/*.o - -rm -f build/primitives/*.P - -rm -f build/script/*.o - -rm -f build/script/*.P - -rm -f build/support/*.o - -rm -f build/support/*.P - -rm -f build/univalue/*.o - -rm -f build/univalue/*.P - -rm -f build/wallet/*.o - -rm -f build/wallet/*.P - cd leveldb && make clean - - - -FORCE: diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index f4b7a3a7..b91705ee 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -5,9 +5,9 @@ #include "merkleblock.h" -#include "hash.h" +#include "crypto/hash.h" #include "consensus/consensus.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter) { diff --git a/src/merkleblock.h b/src/merkleblock.h index bde1191c..4ab5598f 100644 --- a/src/merkleblock.h +++ b/src/merkleblock.h @@ -6,9 +6,7 @@ #ifndef BITCOIN_MERKLEBLOCK_H #define BITCOIN_MERKLEBLOCK_H -#include "serialize.h" -#include "uint256.h" -#include "primitives/block.h" +#include "chain/block.h" #include "bloom.h" #include @@ -85,7 +83,7 @@ class CPartialMerkleTree ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nTransactions); READWRITE(vHash); std::vector vBytes; @@ -147,7 +145,7 @@ class CMerkleBlock ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(header); READWRITE(txn); } diff --git a/src/messages.cpp b/src/messages.cpp index 0a2d1d78..9cddf80b 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -1,24 +1,29 @@ +// Copyright (c) 2017 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "messages.h" #include "serialize.h" #include "sync.h" -#include "primitives/block.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include "txmempool.h" #include "main.h" -#include "util.h" +#include "util/util.h" #include "args.h" #include "addrman.h" #include "version.h" #include "protocol.h" #include "merkleblock.h" #include "validationinterface.h" -#include "utilstrencodings.h" -#include "chain.h" +#include "util/utilstrencodings.h" +#include "chain/chain.h" #include "consensus/validation.h" -#include "chainparams.h" +#include "networks/networktemplate.h" +#include "networks/netman.h" #include "processblock.h" #include "processheader.h" +#include "init.h" #include #include @@ -32,6 +37,28 @@ // Messages // +/** + * Filter for transactions that were recently rejected by + * AcceptToMemoryPool. These are not rerequested until the chain tip + * changes, at which point the entire filter is reset. Protected by + * cs_main. + * + * Without this filter we'd be re-requesting txs from each of our peers, + * increasing bandwidth consumption considerably. For instance, with 100 + * peers, half of which relay a tx we don't accept, that might be a 50x + * bandwidth increase. A flooding attacker attempting to roll-over the + * filter using minimum-sized, 60byte, transactions might manage to send + * 1000/sec if we have fast peers, so we pick 120,000 to give our peers a + * two minute window to send invs to us. + * + * Decreasing the false positive rate is fairly cheap, so we pick one in a + * million to make it highly unlikely for users to have issues with this + * filter. + * + * Memory used: 1.3 MB + */ +std::unique_ptr recentRejects; + uint256 hashRecentRejectsChainTip; @@ -40,14 +67,17 @@ uint256 hashRecentRejectsChainTip; bool MarkBlockAsReceived(const uint256& hash) { std::map::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); - if (itInFlight != mapBlocksInFlight.end()) { + if (itInFlight != mapBlocksInFlight.end()) + { CNodeState *state = State(itInFlight->second.first); state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders; - if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) { + if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) + { // Last validated block on the queue was received. nPeersWithValidatedDownloads--; } - if (state->vBlocksInFlight.begin() == itInFlight->second.second) { + if (state->vBlocksInFlight.begin() == itInFlight->second.second) + { // First block on the queue was received, update the start download time for the next one state->nDownloadingSince = std::max(state->nDownloadingSince, GetTimeMicros()); } @@ -82,7 +112,7 @@ CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) { // Requires cs_main bool CanDirectFetch(const Consensus::Params &consensusParams) { - return chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nTargetSpacing * 20; + return pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nTargetSpacing * 20; } bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main) @@ -98,7 +128,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c // have been mined or received. // 10,000 orphans, each of which is at most 5,000 bytes big is // at most 500 megabytes of orphans: - unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); + unsigned int sz = GetSerializeSize(tx, SER_NETWORK, CTransaction::CURRENT_VERSION); if (sz > 5000) { LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); @@ -194,8 +224,8 @@ void ProcessBlockAvailability(NodeId nodeid) { assert(state != NULL); if (!state->hashLastUnknownBlock.IsNull()) { - BlockMap::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock); - if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) { + BlockMap::iterator itOld = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(state->hashLastUnknownBlock); + if (itOld != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end() && itOld->second->nChainWork > 0) { if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) state->pindexBestKnownBlock = itOld->second; state->hashLastUnknownBlock.SetNull(); @@ -226,7 +256,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectorpindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork) { + if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nChainWork) { // This peer has nothing interesting. return; } @@ -234,7 +264,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectorpindexLastCommonBlock == NULL) { // Bootstrap quickly by guessing a parent of our best tip is the forking point. // Guessing wrong in either direction is not a problem. - state->pindexLastCommonBlock = chainActive[std::min(state->pindexBestKnownBlock->nHeight, chainActive.Height())]; + state->pindexLastCommonBlock = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive[std::min(state->pindexBestKnownBlock->nHeight, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height())]; } // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor @@ -272,7 +302,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectornStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) { + if (pindex->nStatus & BLOCK_HAVE_DATA || pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(pindex)) { if (pindex->nChainTx) state->pindexLastCommonBlock = pindex; } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) { @@ -314,8 +344,8 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { ProcessBlockAvailability(nodeid); - BlockMap::iterator it = mapBlockIndex.find(hash); - if (it != mapBlockIndex.end() && it->second->nChainWork > 0) { + BlockMap::iterator it = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(hash); + if (it != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end() && it->second->nChainWork > 0) { // An actually better block was announced. if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) state->pindexBestKnownBlock = it->second; @@ -332,23 +362,23 @@ bool AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) case MSG_TX: { assert(recentRejects); - if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip) + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip) { // If the chain tip has changed previously rejected transactions // might be now valid, e.g. due to a nLockTime'd tx becoming valid, // or a double-spend. Reset the rejects filter and give those // txs a second chance. - hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHash(); + hashRecentRejectsChainTip = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash(); recentRejects->reset(); } return recentRejects->contains(inv.hash) || mempool.exists(inv.hash) || mapOrphanTransactions.count(inv.hash) || - pcoinsTip->HaveCoins(inv.hash); + pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->HaveCoins(inv.hash); } case MSG_BLOCK: - return mapBlockIndex.count(inv.hash); + return pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(inv.hash); } // Don't know what it is, just say we already got one return true; @@ -375,19 +405,19 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) { bool send = false; - BlockMap::iterator mi = mapBlockIndex.find(inv.hash); - if (mi != mapBlockIndex.end()) + BlockMap::iterator mi = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(inv.hash); + if (mi != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) { - if (chainActive.Contains(mi->second)) { + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(mi->second)) { send = true; } else { static const int nOneMonth = 30 * 24 * 60 * 60; // To prevent fingerprinting attacks, only send blocks outside of the active // chain if they are valid, and no more than a month older (both in time, and in // best equivalent proof of work) than the best header chain we know about. - send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) && - (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) && - (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, consensusParams) < nOneMonth); + send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader != NULL) && + (pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) && + (GetBlockProofEquivalentTime(*pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader, *mi->second, *pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader, consensusParams) < nOneMonth); if (!send) { LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId()); } @@ -396,7 +426,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // disconnect node in case we have reached the outbound limit for serving historical blocks // never disconnect whitelisted nodes static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical - if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) + if (send && CNode::OutboundTargetReached(true) && ( ((pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader != NULL) && (pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) { LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); @@ -442,7 +472,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // and we want it right after the last block so they don't // wait for other stuff first. std::vector vInv; - vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash())); + vInv.push_back(CInv(MSG_BLOCK, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash())); pfrom->PushMessage(NetMsgType::INV, vInv); pfrom->hashContinue.SetNull(); } @@ -499,10 +529,10 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vRecv, int64_t nTimeReceived) { - const CChainParams& chainparams = Params(); + const CNetworkTemplate& chainparams = pnetMan->getActivePaymentNetwork(); RandAddSeedPerfmon(); LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); - if (gArgs.IsArgSet("-dropmessagestest") && GetRand(atoi(gArgs.GetArg("-dropmessagestest", 0))) == 0) + if (gArgs.IsArgSet("-dropmessagestest") && GetRand(atoi(gArgs.GetArg("-dropmessagestest", "0"))) == 0) { LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n"); return true; @@ -594,7 +624,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR if (!pfrom->fInbound) { // Advertise our address - if (fListen && !IsInitialBlockDownload()) + if (fListen && !pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload()) { CAddress addr = GetLocalAddress(&pfrom->addr); if (addr.IsRoutable()) @@ -780,7 +810,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR } else { - pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash); + pfrom->PushMessage(NetMsgType::GETHEADERS, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.GetLocator(pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader), inv.hash); CNodeState *nodestate = State(pfrom->GetId()); if (CanDirectFetch(chainparams.GetConsensus()) && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { @@ -790,7 +820,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR MarkBlockAsInFlight(pfrom->GetId(), inv.hash, chainparams.GetConsensus()); } } - LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); + LogPrint("net", "getheaders (%d) %s to peer=%d\n", pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); } } else @@ -843,14 +873,14 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR LOCK(cs_main); // Find the last block the caller has in the main chain - CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator); + CBlockIndex* pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->FindForkInGlobalIndex(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive, locator); // Send the rest of the chain if (pindex) - pindex = chainActive.Next(pindex); + pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Next(pindex); int nLimit = 500; LogPrint("net", "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom->id); - for (; pindex; pindex = chainActive.Next(pindex)) + for (; pindex; pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Next(pindex)) { if (pindex->GetBlockHash() == hashStop) { @@ -878,7 +908,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR vRecv >> locator >> hashStop; LOCK(cs_main); - if (IsInitialBlockDownload() && !pfrom->fWhitelisted) { + if (pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload() && !pfrom->fWhitelisted) { LogPrint("net", "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->id); return true; } @@ -888,24 +918,24 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR if (locator.IsNull()) { // If locator is null, return the hashStop block - BlockMap::iterator mi = mapBlockIndex.find(hashStop); - if (mi == mapBlockIndex.end()) + BlockMap::iterator mi = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(hashStop); + if (mi == pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) return true; pindex = (*mi).second; } else { // Find the last block the caller has in the main chain - pindex = FindForkInGlobalIndex(chainActive, locator); + pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->FindForkInGlobalIndex(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive, locator); if (pindex) - pindex = chainActive.Next(pindex); + pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Next(pindex); } // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end std::vector vHeaders; int nLimit = MAX_HEADERS_RESULTS; LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id); - for (; pindex; pindex = chainActive.Next(pindex)) + for (; pindex; pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Next(pindex)) { vHeaders.push_back(pindex->GetBlockHeader()); if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) @@ -915,7 +945,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR // if our peer has chainActive.Tip() (and thus we are sending an empty // headers message). In both cases it's safe to update // pindexBestHeaderSent to be our tip. - nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip(); + nodestate->pindexBestHeaderSent = pindex ? pindex : pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); pfrom->PushMessage(NetMsgType::HEADERS, vHeaders); } @@ -940,7 +970,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) { - mempool.check(pcoinsTip); + mempool.check(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get()); RelayTransaction(tx); vWorkQueue.push_back(inv.hash); @@ -996,7 +1026,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR assert(recentRejects); recentRejects->insert(orphanHash); } - mempool.check(pcoinsTip); + mempool.check(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get()); } } @@ -1100,18 +1130,18 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue // from there instead. LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight); - pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()); + pfrom->PushMessage(NetMsgType::GETHEADERS, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.GetLocator(pindexLast), uint256()); } bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); CNodeState *nodestate = State(pfrom->GetId()); // If this set of headers is valid and ends in a block with at least as // much work as our tip, download as much as possible. - if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { + if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { std::vector vToFetch; CBlockIndex *pindexWalk = pindexLast; // Calculate all the blocks we'd need to switch to pindexLast, up to a limit. - while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + while (pindexWalk && !pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && !mapBlocksInFlight.count(pindexWalk->GetBlockHash())) { // We don't have this block, and it's not yet in flight. @@ -1123,7 +1153,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR // very large reorg at a time we think we're close to caught up to // the main chain -- this shouldn't really happen. Bail out on the // direct fetch and rely on parallel download instead. - if (!chainActive.Contains(pindexWalk)) { + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(pindexWalk)) { LogPrint("net", "Large reorg, won't direct fetch to %s (%d)\n", pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); @@ -1168,7 +1198,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR // unless we're still syncing with the network. // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). - bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); + bool forceProcessing = pfrom->fWhitelisted && !pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload(); ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, RECEIVED); int nDoS; if (state.IsInvalid(nDoS)) @@ -1185,7 +1215,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR { uint256 emptyHash; emptyHash.SetNull(); - pfrom->PushMessage(NetMsgType::GETBLOCKS, chainActive.GetLocator(chainActive.Tip()), emptyHash); + pfrom->PushMessage(NetMsgType::GETBLOCKS, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.GetLocator(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()), emptyHash); } } } @@ -1400,7 +1430,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR // requires LOCK(cs_vRecvMsg) bool ProcessMessages(CNode* pfrom) { - const CChainParams& chainparams = Params(); + const CNetworkTemplate& chainparams = pnetMan->getActivePaymentNetwork(); //if (fDebug) // LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size()); @@ -1525,7 +1555,7 @@ bool ProcessMessages(CNode* pfrom) bool SendMessages(CNode* pto) { - const Consensus::Params& consensusParams = Params().GetConsensus(); + const Consensus::Params& consensusParams = pnetMan->getActivePaymentNetwork()->GetConsensus(); { // Don't send anything until we get its version message if (pto->nVersion == 0) @@ -1560,7 +1590,7 @@ bool SendMessages(CNode* pto) // Address refresh broadcast int64_t nNow = GetTimeMicros(); - if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) { + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) { AdvertizeLocal(pto); pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); } @@ -1612,16 +1642,16 @@ bool SendMessages(CNode* pto) state.rejects.clear(); // Start block sync - if (pindexBestHeader == NULL) - pindexBestHeader = chainActive.Tip(); + if (pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader == NULL) + pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do. if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { // Only actively request headers from a single peer, unless we're close to today. - if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { + if ((nSyncStarted == 0 && fFetch) || pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { state.fSyncStarted = true; nSyncStarted++; - const CBlockIndex *pindexStart = pindexBestHeader; + const CBlockIndex *pindexStart = pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader; /* If possible, start at the block preceding the currently best known header. This ensures that we always get a non-empty list of headers back as long as the peer @@ -1634,11 +1664,11 @@ bool SendMessages(CNode* pto) LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight); if(pto->nVersion >= GETHEADERS_VERSION) { - pto->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()); + pto->PushMessage(NetMsgType::GETHEADERS, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.GetLocator(pindexStart), uint256()); } else { - pto->PushMessage(NetMsgType::GETBLOCKS, chainActive.GetLocator(pindexStart), uint256()); + pto->PushMessage(NetMsgType::GETBLOCKS, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.GetLocator(pindexStart), uint256()); } } } @@ -1646,7 +1676,7 @@ bool SendMessages(CNode* pto) // Resend wallet transactions that haven't gotten in a block yet // Except during reindex, importing and IBD, when old wallet // transactions become unconfirmed and spams other nodes. - if (!fReindex && !fImporting && !IsInitialBlockDownload()) + if (!fReindex && !fImporting && !pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload()) { GetMainSignals().Broadcast(nTimeBestReceived); } @@ -1674,10 +1704,10 @@ bool SendMessages(CNode* pto) // then send all headers past that one. If we come across any // headers that aren't on chainActive, give up. for(const uint256 &hash : pto->vBlockHashesToAnnounce) { - BlockMap::iterator mi = mapBlockIndex.find(hash); - assert(mi != mapBlockIndex.end()); + BlockMap::iterator mi = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(hash); + assert(mi != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()); CBlockIndex *pindex = mi->second; - if (chainActive[pindex->nHeight] != pindex) { + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive[pindex->nHeight] != pindex) { // Bail out if we reorged away from this block fRevertToInv = true; break; @@ -1708,16 +1738,16 @@ bool SendMessages(CNode* pto) // in the past. if (!pto->vBlockHashesToAnnounce.empty()) { const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back(); - BlockMap::iterator mi = mapBlockIndex.find(hashToAnnounce); - assert(mi != mapBlockIndex.end()); + BlockMap::iterator mi = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(hashToAnnounce); + assert(mi != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()); CBlockIndex *pindex = mi->second; // Warn if we're announcing a block that is not on the main chain. // This should be very rare and could be optimized out. // Just log for now. - if (chainActive[pindex->nHeight] != pindex) { + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive[pindex->nHeight] != pindex) { LogPrint("net", "Announcing block %s not on main chain (tip=%s)\n", - hashToAnnounce.ToString(), chainActive.Tip()->GetBlockHash().ToString()); + hashToAnnounce.ToString(), pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash().ToString()); } // If the peer announced this block to us, don't inv it back. @@ -1823,7 +1853,7 @@ bool SendMessages(CNode* pto) // Message: getdata (blocks) // std::vector vGetData; - if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + if (!pto->fDisconnect && !pto->fClient && (fFetch || !pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { std::vector vToDownload; NodeId staller = -1; FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller); diff --git a/src/messages.h b/src/messages.h index caf297e3..8da0607b 100644 --- a/src/messages.h +++ b/src/messages.h @@ -1,11 +1,28 @@ +// Copyright (c) 2017 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef MESSAGES_H #define MESSAGES_H #include "net.h" +#include "chain/blockindex.h" + +extern std::unique_ptr recentRejects; +/** Process protocol messages received from a given node */ bool ProcessMessages(CNode* pfrom); + +/** + * Send queued protocol messages to be sent to a give node. + * + * @param[in] pto The node which we are sending messages to. + */ bool SendMessages(CNode* pto); + +/** Returns a bool indicating whether we requested this block. If we did request it, marks it as receieved and removes block from in flight list*/ bool MarkBlockAsReceived(const uint256& hash); +CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb); #endif // MESSAGES_H diff --git a/src/miner.cpp b/src/miner.cpp index 567887b4..465c7c41 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -9,19 +9,20 @@ #include "kernel.h" #include "crypto/scrypt.h" #include "txmempool.h" -#include "util.h" +#include "util/util.h" #include "args.h" #include "init.h" #include "consensus/consensus.h" #include "txmempool.h" -#include "utilmoneystr.h" +#include "util/utilmoneystr.h" #include "timedata.h" #include "bignum.h" #include "coins.h" -#include "chainparams.h" +#include "networks/networktemplate.h" #include "consensus/validation.h" #include "consensus/merkle.h" #include "processblock.h" +#include "networks/netman.h" #include #include @@ -208,7 +209,7 @@ CBlockTemplate* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) // ppcoin: if coinstake available add coinstake tx static int64_t nLastCoinStakeSearchTime = GetAdjustedTime(); // only initialized at startup - CBlockIndex* pindexPrev = chainActive.Tip(); + CBlockIndex* pindexPrev = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); // This vector will be sorted into a priority queue: @@ -259,7 +260,7 @@ CBlockTemplate* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) // Collect memory pool transactions into the block { LOCK2(cs_main, mempool.cs); - CBlockIndex* pindexPrev = chainActive.Tip(); + CBlockIndex* pindexPrev = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); const int nHeight = pindexPrev->nHeight + 1; pblock->nTime = GetAdjustedTime(); const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); @@ -497,7 +498,7 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) // Found a solution { LOCK(cs_main); - if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash()) + if (pblock->hashPrevBlock != pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash()) return error("BMiner : generated block is stale"); // Remove key from key pool @@ -511,7 +512,7 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) // Process this block the same as if we had received it from another node CValidationState state; - const CChainParams& chainparams = Params(); + const CNetworkTemplate& chainparams = pnetMan->getActivePaymentNetwork(); if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, GENERATED)) return error("Miner : ProcessBlock, block not accepted"); } @@ -539,7 +540,7 @@ void ScryptMiner(CWallet *pwallet) { if (fShutdown) return; - while (vNodes.empty() || vNodes.size() < 6 || IsInitialBlockDownload()) + while (vNodes.empty() || vNodes.size() < 6 || pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload()) { MilliSleep(1000); if (fShutdown) @@ -557,7 +558,7 @@ void ScryptMiner(CWallet *pwallet) // Create new block // unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrev = chainActive.Tip(); + CBlockIndex* pindexPrev = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); std::auto_ptr pblocktemplate(CreateNewBlock(pwallet, true)); if (!pblocktemplate.get()) @@ -682,7 +683,7 @@ void ScryptMiner(CWallet *pwallet) break; if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) break; - if (pindexPrev != chainActive.Tip()) + if (pindexPrev != pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()) break; // Update nTime every few seconds @@ -720,11 +721,11 @@ void ThreadScryptMiner(void* parg) minerThreads->create_thread(boost::bind(&ScryptMiner, pwallet)); } catch (std::exception& e) { - PrintException(&e, "ThreadBitcoinMiner()"); + PrintException(&e, "ThreadECCMinter()"); } catch (...) { - PrintException(NULL, "ThreadBitcoinMiner()"); + PrintException(NULL, "ThreadECCMinter()"); } nHPSTimerStart = 0; dHashesPerSec = 0; - LogPrintf("ThreadBitcoinMiner exiting \n"); + LogPrintf("ThreadECCMinter exiting \n"); } diff --git a/src/miner.h b/src/miner.h index 3d80b6f0..14e7b924 100644 --- a/src/miner.h +++ b/src/miner.h @@ -12,8 +12,6 @@ extern int64_t nLastCoinStakeSearchInterval; static const bool DEFAULT_GENERATE = false; -static const int DEFAULT_GENERATE_THREADS = 1; - static const bool DEFAULT_PRINTPRIORITY = false; diff --git a/src/net.cpp b/src/net.cpp index 041a0bee..6cbe151c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -3,23 +3,20 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #include "net.h" #include "args.h" #include "addrman.h" -#include "chainparams.h" +#include "networks/netman.h" #include "clientversion.h" #include "consensus/consensus.h" #include "crypto/common.h" -#include "hash.h" -#include "primitives/transaction.h" +#include "crypto/hash.h" +#include "tx/tx.h" #include "scheduler.h" #include "ui_interface.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" +#include "init.h" #ifdef WIN32 #include @@ -120,7 +117,7 @@ void AddOneShot(const std::string& strDest) unsigned short GetListenPort() { - return (unsigned short)(gArgs.GetArg("-port", Params().GetDefaultPort())); + return (unsigned short)(gArgs.GetArg("-port", pnetMan->getActivePaymentNetwork()->GetDefaultPort())); } // find 'best' local address for a particular peer @@ -359,6 +356,7 @@ CNode* FindNode(const CService& addr) CNode* ConnectNode(CAddress addrConnect, const char *pszDest) { + bool fCountFailure = false; if (pszDest == NULL) { if (IsLocal(addrConnect)) return NULL; @@ -380,7 +378,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) // Connect SOCKET hSocket; bool proxyConnectionFailed = false; - if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, Params().GetDefaultPort(), nConnectTimeout, &proxyConnectionFailed) : + if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, pnetMan->getActivePaymentNetwork()->GetDefaultPort(), nConnectTimeout, &proxyConnectionFailed) : ConnectSocket(addrConnect, hSocket, nConnectTimeout, &proxyConnectionFailed)) { if (!IsSelectableSocket(hSocket)) { @@ -389,7 +387,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) return NULL; } - addrman.Attempt(addrConnect); + addrman.Attempt(addrConnect, fCountFailure); // Add node CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); @@ -406,7 +404,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) } else if (!proxyConnectionFailed) { // If connecting to the node failed, and failure is not caused by a problem connecting to // the proxy, mark this as an attempt. - addrman.Attempt(addrConnect); + addrman.Attempt(addrConnect, fCountFailure); } return NULL; @@ -639,7 +637,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) // get current incomplete message, or create a new one if (vRecvMsg.empty() || vRecvMsg.back().complete()) - vRecvMsg.push_back(CNetMessage(Params().MessageStart(), SER_NETWORK, nRecvVersion)); + vRecvMsg.push_back(CNetMessage(pnetMan->getActivePaymentNetwork()->MessageStart(), SER_NETWORK, nRecvVersion)); CNetMessage& msg = vRecvMsg.back(); @@ -1141,7 +1139,12 @@ void ThreadSocketHandler() int nErr = WSAGetLastError(); LogPrintf("socket select error %s\n", NetworkErrorString(nErr)); for (unsigned int i = 0; i <= hSocketMax; i++) - FD_SET(i, &fdsetRecv); + { + if(FD_ISSET(i, &fdsetRecv)) + { + FD_SET(i, &fdsetRecv); + } + } } FD_ZERO(&fdsetSend); FD_ZERO(&fdsetError); @@ -1405,7 +1408,7 @@ void ThreadDNSAddressSeed() } } - const std::vector &vSeeds = Params().DNSSeeds(); + const std::vector &vSeeds = pnetMan->getActivePaymentNetwork()->DNSSeeds(); int found = 0; LogPrintf("Loading addresses from DNS seeds (could take a while)\n"); @@ -1421,7 +1424,7 @@ void ThreadDNSAddressSeed() for (auto const& ip: vIPs) { int nOneDay = 24*3600; - CAddress addr = CAddress(CService(ip, Params().GetDefaultPort())); + CAddress addr = CAddress(CService(ip, pnetMan->getActivePaymentNetwork()->GetDefaultPort())); addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old vAdd.push_back(addr); found++; @@ -1561,7 +1564,7 @@ void ThreadOpenConnections() continue; // do not allow non-default ports, unless after 50 invalid addresses selected already - if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50) + if (addr.GetPort() != pnetMan->getActivePaymentNetwork()->GetDefaultPort() && nTries < 50) continue; addrConnect = addr; @@ -1610,7 +1613,7 @@ void ThreadOpenAddedConnections() std::list > lservAddressesToAdd(0); for (auto const& strAddNode: lAddresses) { std::vector vservNode(0); - if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) + if(Lookup(strAddNode.c_str(), vservNode, pnetMan->getActivePaymentNetwork()->GetDefaultPort(), fNameLookup, 0)) { lservAddressesToAdd.push_back(vservNode); { @@ -2219,7 +2222,7 @@ bool CAddrDB::Write(const CAddrMan& addr) // serialize addresses, checksum data up to that point, then append csum CDataStream ssPeers(SER_DISK, CLIENT_VERSION); - ssPeers << FLATDATA(Params().MessageStart()); + ssPeers << FLATDATA(pnetMan->getActivePaymentNetwork()->MessageStart()); ssPeers << addr; uint256 hash = Hash(ssPeers.begin(), ssPeers.end()); ssPeers << hash; @@ -2289,7 +2292,7 @@ bool CAddrDB::Read(CAddrMan& addr) ssPeers >> FLATDATA(pchMsgTmp); // ... verify the network matches ours - if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) + if (memcmp(pchMsgTmp, pnetMan->getActivePaymentNetwork()->MessageStart(), sizeof(pchMsgTmp))) return error("%s: Invalid network magic number", __func__); // de-serialize address data into one CAddrMan object @@ -2413,7 +2416,7 @@ void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSen { ENTER_CRITICAL_SECTION(cs_vSend); assert(ssSend.size() == 0); - ssSend << CMessageHeader(Params().MessageStart(), pszCommand, 0); + ssSend << CMessageHeader(pnetMan->getActivePaymentNetwork()->MessageStart(), pszCommand, 0); LogPrint("net", "sending: %s ", SanitizeString(pszCommand)); } @@ -2487,7 +2490,7 @@ bool CBanDB::Write(const banmap_t& banSet) // serialize banlist, checksum data up to that point, then append csum CDataStream ssBanlist(SER_DISK, CLIENT_VERSION); - ssBanlist << FLATDATA(Params().MessageStart()); + ssBanlist << FLATDATA(pnetMan->getActivePaymentNetwork()->MessageStart()); ssBanlist << banSet; uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end()); ssBanlist << hash; @@ -2557,7 +2560,7 @@ bool CBanDB::Read(banmap_t& banSet) ssBanlist >> FLATDATA(pchMsgTmp); // ... verify the network matches ours - if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) + if (memcmp(pchMsgTmp, pnetMan->getActivePaymentNetwork()->MessageStart(), sizeof(pchMsgTmp))) return error("%s: Invalid network magic number", __func__); // de-serialize address data into one CAddrMan object diff --git a/src/net.h b/src/net.h index 66632c66..df2c1079 100644 --- a/src/net.h +++ b/src/net.h @@ -6,8 +6,9 @@ #ifndef BITCOIN_NET_H #define BITCOIN_NET_H -#include "bloom.h" #include "compat.h" + +#include "bloom.h" #include "limitedmap.h" #include "netbase.h" #include "protocol.h" @@ -276,7 +277,7 @@ class CBanEntry ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(nCreateTime); diff --git a/src/netbase.cpp b/src/netbase.cpp index 4e1f2676..363d3e51 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -9,12 +9,12 @@ #include "netbase.h" -#include "hash.h" +#include "crypto/hash.h" #include "sync.h" #include "uint256.h" #include "random.h" -#include "util.h" -#include "utilstrencodings.h" +#include "util/util.h" +#include "util/utilstrencodings.h" #ifdef HAVE_GETADDRINFO_A #include diff --git a/src/netbase.h b/src/netbase.h index c2bc2c42..cfbaff67 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -5,10 +5,6 @@ #ifndef BITCOIN_NETBASE_H #define BITCOIN_NETBASE_H -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #include "compat.h" #include "serialize.h" @@ -99,7 +95,7 @@ class CNetAddr ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(FLATDATA(ip)); } @@ -135,7 +131,7 @@ class CSubNet ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(network); READWRITE(FLATDATA(netmask)); READWRITE(FLATDATA(valid)); @@ -176,7 +172,7 @@ class CService : public CNetAddr ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(FLATDATA(ip)); unsigned short portN = htons(port); READWRITE(FLATDATA(portN)); diff --git a/src/networks/netman.cpp b/src/networks/netman.cpp new file mode 100644 index 00000000..3c8f8622 --- /dev/null +++ b/src/networks/netman.cpp @@ -0,0 +1,280 @@ +// Copyright (c) 2017 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "netman.h" +#include "tinyformat.h" +#include "util/util.h" +#include "args.h" +#include "consensus/merkle.h" +#include + + +#include + +void AppendParamsHelpMessages(std::string& strUsage, bool debugHelp) +{ + strUsage += HelpMessageGroup(_("Chain selection options:")); + strUsage += HelpMessageOpt("-testnet", _("Use the test chain")); + if (debugHelp) { + strUsage += HelpMessageOpt("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. " + "This is intended for regression testing tools and app development."); + } +} + +void CNetworkManager::ConstructNetworks() +{ + if(legacyTemplate != NULL) + { + pnetLegacy = new CNetwork(legacyTemplate); + } + if(paymentTemplate != NULL) + { + pnetPayment = new CNetwork(paymentTemplate); + } + if(netManTestnetTemplate != NULL) + { + pnetTestnet0 = new CNetwork(netManTestnetTemplate); + } +} + +void CNetworkManager::ConstructLegacyNetworkTemplate() +{ + legacyTemplate->strNetworkID = "LEGACY"; + legacyTemplate->strNetworkDataDir = ""; + legacyTemplate->consensus.nMajorityEnforceBlockUpgrade = 750; + legacyTemplate->consensus.nMajorityRejectBlockOutdated = 950; + legacyTemplate->consensus.nMajorityWindow = 1000; + legacyTemplate->consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + legacyTemplate->consensus.posLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + legacyTemplate->consensus.nTargetTimespan = 30 * 45; + legacyTemplate->consensus.nTargetSpacing = 45; + legacyTemplate->consensus.fPowAllowMinDifficultyBlocks = false; + legacyTemplate->consensus.fPowNoRetargeting = false; + legacyTemplate->consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 + legacyTemplate->consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nTargetSpacing + legacyTemplate->consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; + legacyTemplate->consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 + legacyTemplate->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 + * a large 32-bit integer with any alignment. + */ + legacyTemplate->pchMessageStart[0] = 0xce; + legacyTemplate->pchMessageStart[1] = 0xf1; + legacyTemplate->pchMessageStart[2] = 0xdb; + legacyTemplate->pchMessageStart[3] = 0xfa; + legacyTemplate->nDefaultPort = 19118; + legacyTemplate->nRPCPort = 19119; + legacyTemplate->nMaxTipAge = 24 * 60 * 60; + legacyTemplate->nStakeMaxAge = 60*60*24*84; //84 days + legacyTemplate->nStakeMinAge = 60*60*2; // 2 hours + + const char* pszTimestamp = "AP | Mar 2, 2014, 10.35 AM IST: China blames Uighur separatists for knife attack; 33 dead"; + CTransaction txNew; + txNew.nTime = 1393744287; + txNew.vin.resize(1); + txNew.vout.resize(1); + txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(9999) << std::vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vout[0].SetEmpty(); + txNew.vout[0].SetEmpty(); + + legacyTemplate->genesis.vtx.push_back(txNew); + legacyTemplate->genesis.hashPrevBlock.SetNull(); + legacyTemplate->genesis.nVersion = 1; + legacyTemplate->genesis.nTime = 1393744307; + legacyTemplate->genesis.nBits = 0x1e0fffff; + legacyTemplate->genesis.nNonce = 12799721; + legacyTemplate->genesis.hashMerkleRoot = BlockMerkleRoot(legacyTemplate->genesis); + + legacyTemplate->consensus.hashGenesisBlock = legacyTemplate->genesis.GetHash(); + assert(legacyTemplate->consensus.hashGenesisBlock == uint256S("0xa60ac43c88dbc44b826cf315352a8a7b373d2af8b6e1c4c4a0638859c5e9ecd1")); + assert(legacyTemplate->genesis.hashMerkleRoot == uint256S("0x4db82fe8b45f3dae2b7c7b8be5ec4c37e72e25eaf989b9db24ce1d0fd37eed8b")); + + legacyTemplate->vSeeds.push_back(CDNSSeedData("CryptoUnitedSeed", "www.cryptounited.io")); + legacyTemplate->vSeeds.push_back(CDNSSeedData("ECC-Seed1", "138.197.100.45")); + legacyTemplate->vSeeds.push_back(CDNSSeedData("ECC-Seed2", "159.203.172.212")); + legacyTemplate->vSeeds.push_back(CDNSSeedData("ECC-Seed3", "eccnode.altj.com")); + + legacyTemplate->base58Prefixes[CNetworkTemplate::PUBKEY_ADDRESS] = std::vector(1,33); + legacyTemplate->base58Prefixes[CNetworkTemplate::SCRIPT_ADDRESS] = std::vector(1,8); + legacyTemplate->base58Prefixes[CNetworkTemplate::SECRET_KEY] = std::vector(1,161); + legacyTemplate->base58Prefixes[CNetworkTemplate::EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container >(); + legacyTemplate->base58Prefixes[CNetworkTemplate::EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container >(); + + legacyTemplate->fMiningRequiresPeers = true; + legacyTemplate->fDefaultConsistencyChecks = false; + legacyTemplate->fRequireStandard = true; + legacyTemplate->fMineBlocksOnDemand = false; + legacyTemplate->fTestnetToBeDeprecatedFieldRPC = false; + + legacyTemplate->checkpointData = (CCheckpointData){ + boost::assign::map_list_of + ( 0, uint256S("0xa60ac43c88dbc44b826cf315352a8a7b373d2af8b6e1c4c4a0638859c5e9ecd1")) + ( 1, uint256S("0x00000762d19a3a38458e73de6c937fd483f17bd75f55d7fe4e95713f51d6b816")) + ( 2, uint256S("0x00000ea50ea0cae64779ff4bb4a0ee94841e2ee20642641a062cbdd342e0a3c5")) + ( 3, uint256S("0x00000513cc6f4bec8d7e7bd0ded854200b6c784c8c830a3e4fd0cccc2cb9e58c")) + ( 1000, uint256S("0x000000000df3f7a5f719c247782d7a43d75186ebc043341e2668320f9d940bcd")) + ( 10000, uint256S("0x00000000076d45a9579c879d46354dd81eeba7060a9a065e13c9dd1c28f474d1")) + ( 23920, uint256S("0x000000000331540c766c4ac667a6fbc65ff93f5a30fbb0c6822986885b1b56c0")) + ( 36918, uint256S("0x0000000001353725582b099cdd3c89933bbd08a17ace464fba935ecfc41572ef")) + ( 50000, uint256S("0x0000000001c770384cd12a74eb5456358425fc6a94a250c3466aaa2ca7460131")) + ( 86401, uint256S("0x51bb1ac3ffd009c12791b9d4320dec0ba69e15c8b6d03d17889b0c09fb5b05a4")) + ( 86402, uint256S("0xa9f3141e571231e02b4fb649370af6173e1a80a9e0d21aa8859bd17ce1260a05")) + ( 86403, uint256S("0xf6c11aadca44fce2390107e229d4d0d70f7cf64266b959672711c68e0f411af5")) + ( 86759, uint256S("0x5c6ed2e23ccc27d59a0659a9a32a4c0ca97d829249277c6a35918f4ec94b1748")) + ( 86761, uint256S("0xca305a45c9f8a89c050f004d0438b38f190fe6bfe51128f0c3e864ddcf2c765c")) + ( 86901, uint256S("0xe769d38b7e140267b688f9d9cc6b58d38185427facb6a1aa719db60a0d54f3f7")) + ( 87000, uint256S("0xbb069ba59aa5a6acc68413ef7c2d0c009b061daf160edf958738d197a059f11d")) + ( 87101, uint256S("0x1ffbfd2a70e626d5f848775851e6f89bee6f2225ed78131b16f9547449d2e2ee")) + ( 96500, uint256S("0x13f0755045a3ae90d33c4bcf6ba1581025fc6e0caf46f7624063cb59dcc3d27c")) + (100000, uint256S("0x28a483386650a188c3346fd5e329e2c8cc137cf3557547e8525f5cdea601501a")) + (136500, uint256S("0x7e4ec82a165762e8a324038ef1cdd0b83e603f4737ae6f9e5967b13b8b6ace5c")) + (150000, uint256S("0xfee6d00910e8d0aa2f0ca8a447b4de366a12f9df2521f77c5a97a5ae0af8834e")) + (185000, uint256S("0xce904504a0df58944c6a633b739abcec3bbb256b510a616b465c24525d564828")) + (197712, uint256S("0x7576d0f370b1efdce01075a9491fb8d2f98af485f78d170196270f1eb156ee40")) + (200000, uint256S("0x1f1ea51aee8a7456655e31857c7cd4a9f494556438485abd4c60d86cacf24b44")) + (205000, uint256S("0x9e4528bc818bb1ee2cdf44ba7805e88b4fc85bbf496516f35d4d642c6812503e")) + (209762, uint256S("0x49448f382f9ec8f126542244573e7349c7b07db0cbdc2ab8326942cbfff603b3")) + (209786, uint256S("0x28558eedf7f5c049e9f2ea61da270fffc5b50310aafb29c7595840784e8b1d61")) + (215650, uint256S("0xd7fb37df6be4bf2c5c9ea47ba4a14f9af35c326cd225122b03f61b74d1283d09")) + (215690, uint256S("0x8af4d5450c238460a4775b19c94872eaf5664657f702bef53576bc9f77af319d")) + (220504, uint256S("0x5781d160a46a6631a21e62a9a67932d0f9b8636c8f5241973b076db3854de405")) + (221000, uint256S("0x51cd22cde58a3738e851f155a282b4624d3e18e84fbcb02de5006029dec8f7e3")) + (233855, uint256S("0x77c1312f0b4ba0fc34cb7a0f3472012739bbd22c317add69edaa4908e83b00eb")) + (236850, uint256S("0x139203f72c943433880c4f8d3581a4cb7ee0877f341639cd4c7810edc7fc7d80")) + (237000, uint256S("0x70fdb4f39e571afff137c7bd40c4df98ccab32cec1d305074bac9fca30754bc0")) + (241130, uint256S("0xdd900777cb9e2ea2cae0bf410ce2f2484a415c7bf7af59d9492868195583e3b2")) + (242150, uint256S("0xba96de8da95ac53cedc7fd0cd3c17b32f5d3a04f33a544060606c095b28bf4c1")) + (300000, uint256S("0x2c654dfa9f1ab51a64509910b1f053fc20d572022480814988c36f042cb3010b")) + (350000, uint256S("0xfdb1df53f4365d494d9fa54247a533cbfcd9b6992491f40c8ccfeed454932a70")) + (400000, uint256S("0xc04d360938d5ff66294100a10424f7e284abe76d117f28460e16752edeb03444")) + (435000, uint256S("0x801a211aa479129e42554bc812d624e585e1b0dd608e23b1a7f87a9d14e7fdec")) + (450000, uint256S("0x53e21a2574ff6acc0f31640c4058554dde2fe8972ec72867403e8b88e9ba1bc6")) + (500000, uint256S("0x779f22407cf9fa0adb8a361918ccf249ef913070ce368070c1ac5063005e3e3c")) + (550000, uint256S("0xf340b738c21c0a9b6b2eff0f40d9ab3fca9830d8597131680cd5a2615594cfb0")) + (600000, uint256S("0x589fc3d25c15caaa468dc8b4249e1cbb6ea18368897bd3b1d80f1404486e3783")) + (650000, uint256S("0xc28634f7211ff0582dfe8df1849711a9bd7815005e59dff0059a20876c465f51")) + (675000, uint256S("0xe1aca23bd72ad9d153767272f43d33a0542d2a61a78e281341d0f12cd0521024")) + (675500, uint256S("0x26ccdf8bcb1a50ecef8f507de74ff030789aa1b52491fc4a4de4e4679d53a398")) + (687345, uint256S("0xae2e43c35a3346fa798a0a356ca7a4bce57885ee64e4319295f7f3b7210944f1")) + (700000, uint256S("0x0ab361e8acd391c6b5e726eb4704dd8d60e2e3b3f8856e2f7d6373c9a3e0da36")) + (702950, uint256S("0x26d2cd7b13f1aaa34ffc379696d0e5b14c2ddf8ef2c2c78348fec23f8b55e8ff")) + (1030250,uint256S("0x434ee5c39b6ba186d66cbfaaa8004910b3556726f990b9f33bb48b9fc280c5de")) + (1491250,uint256S("0x45a01a2b45ca91433c8c12378914463bd13afc410b27eeb18855d5b060d7e270")) + (1492500,uint256S("0xd4185d9ae0c38211ac6e0ceddcca4207a00fc59d11b087e76c9bf6d4081856c8")) + (1493040,uint256S("0xcd266ca5eaca1f561d3adf5ab0bc4994ea26418dd12d9072d5c5194639c40ac2")) + }; +} + +void CNetworkManager::ConstructTetnet0Template() +{ + netManTestnetTemplate->strNetworkID = "TESTNET0-TEMPORARY"; + netManTestnetTemplate->strNetworkDataDir = "testnet0-temporary"; + netManTestnetTemplate->consensus.nMajorityEnforceBlockUpgrade = 750; + netManTestnetTemplate->consensus.nMajorityRejectBlockOutdated = 950; + netManTestnetTemplate->consensus.nMajorityWindow = 1000; + netManTestnetTemplate->consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + netManTestnetTemplate->consensus.posLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + netManTestnetTemplate->consensus.nTargetTimespan = 30 * 45; + netManTestnetTemplate->consensus.nTargetSpacing = 45; + netManTestnetTemplate->consensus.fPowAllowMinDifficultyBlocks = false; + netManTestnetTemplate->consensus.fPowNoRetargeting = false; + netManTestnetTemplate->consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 + netManTestnetTemplate->consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nTargetSpacing + netManTestnetTemplate->consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; + netManTestnetTemplate->consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 + netManTestnetTemplate->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 + * a large 32-bit integer with any alignment. + */ + netManTestnetTemplate->pchMessageStart[0] = 0xee; + netManTestnetTemplate->pchMessageStart[1] = 0xff; + netManTestnetTemplate->pchMessageStart[2] = 0xaa; + netManTestnetTemplate->pchMessageStart[3] = 0xbb; + netManTestnetTemplate->nDefaultPort = 30000; + netManTestnetTemplate->nRPCPort = 30001; + netManTestnetTemplate->nMaxTipAge = 24 * 60 * 60; + netManTestnetTemplate->nStakeMaxAge = 60*60*24*84; //84 days + netManTestnetTemplate->nStakeMinAge = 60*2; // 2 minutes + + const char* pszTimestamp = "AP | Dec 3, 2017, Testing of new network manager begins"; + CTransaction txNew; + txNew.nTime = 1512338805; + txNew.vin.resize(1); + txNew.vout.resize(1); + txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(9999) << std::vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vout[0].SetEmpty(); + txNew.vout[0].SetEmpty(); + + netManTestnetTemplate->genesis.vtx.push_back(txNew); + netManTestnetTemplate->genesis.hashPrevBlock.SetNull(); + netManTestnetTemplate->genesis.nVersion = 1; + netManTestnetTemplate->genesis.nTime = 1512338805; + netManTestnetTemplate->genesis.nBits = 0x1e0fffff; + netManTestnetTemplate->genesis.nNonce = 12799721; + netManTestnetTemplate->genesis.hashMerkleRoot = BlockMerkleRoot(netManTestnetTemplate->genesis); + + netManTestnetTemplate->consensus.hashGenesisBlock = netManTestnetTemplate->genesis.GetHash(); + assert(netManTestnetTemplate->consensus.hashGenesisBlock == uint256S("0x94e16dc2de0cec9f52c9e8f1b729b4e1d9d47720eac56388c33e9dec30e52124")); + assert(netManTestnetTemplate->genesis.hashMerkleRoot == uint256S("0xc0e7a1a7812892b4026a3d1a52689180204d742bc968f9d42dddeb338f63cdf0")); + + netManTestnetTemplate->vSeeds.push_back(CDNSSeedData("CryptoUnitedSeed", "www.cryptounited.io")); + + netManTestnetTemplate->base58Prefixes[CNetworkTemplate::PUBKEY_ADDRESS] = std::vector(1,51); + netManTestnetTemplate->base58Prefixes[CNetworkTemplate::SCRIPT_ADDRESS] = std::vector(1,15); + netManTestnetTemplate->base58Prefixes[CNetworkTemplate::SECRET_KEY] = std::vector(1,159); + netManTestnetTemplate->base58Prefixes[CNetworkTemplate::EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container >(); + netManTestnetTemplate->base58Prefixes[CNetworkTemplate::EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container >(); + + netManTestnetTemplate->fMiningRequiresPeers = true; + netManTestnetTemplate->fDefaultConsistencyChecks = false; + netManTestnetTemplate->fRequireStandard = true; + netManTestnetTemplate->fMineBlocksOnDemand = false; + netManTestnetTemplate->fTestnetToBeDeprecatedFieldRPC = false; + + netManTestnetTemplate->checkpointData = (CCheckpointData){ + boost::assign::map_list_of + ( 0, uint256S("0x94e16dc2de0cec9f52c9e8f1b729b4e1d9d47720eac56388c33e9dec30e52124")) + }; +} + +std::string ChainNameFromCommandLine() +{ + bool fRegTest = gArgs.GetBoolArg("-regtest", false); + bool fTestNet = gArgs.GetBoolArg("-testnet0", false); + + if (fTestNet && fRegTest) + throw std::runtime_error("Invalid combination of -regtest and -testnet."); + if (fTestNet) + return "TESTNET0-TEMPORARY"; + return "LEGACY"; +} + +int RPCPortFromCommandLine() +{ + bool fRegTest = gArgs.GetBoolArg("-regtest", false); + bool fTestNet = gArgs.GetBoolArg("-testnet0", false); + + if (fTestNet && fRegTest) + throw std::runtime_error("Invalid combination of -regtest and -testnet."); + if (fTestNet) + return 30001; + return 19119; +} + +void CheckParams(const std::string& network) +{ + if (network != "LEGACY" && network != "TESTNET0-TEMPORARY") + { + throw std::runtime_error(strprintf("%s: Unknown network %s.", __func__, network)); + } + return; +} + + diff --git a/src/networks/netman.h b/src/networks/netman.h new file mode 100644 index 00000000..815de2ec --- /dev/null +++ b/src/networks/netman.h @@ -0,0 +1,104 @@ +// Copyright (c) 2017 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CHAINPARAMSBASE_H +#define BITCOIN_CHAINPARAMSBASE_H + +#include +#include + +#include "network.h" + +/** + * CNetwork defines the base parameters (shared between bitcoin-cli and bitcoind) + * of a given instance of the Bitcoin system. + */ +class CNetworkManager +{ +public: + CNetworkManager() + { + setNull(); + initialize(); + } + + void setNull() + { + legacyTemplate = NULL; + paymentTemplate = NULL; + netManTestnetTemplate = NULL; + + pnetLegacy = NULL; + pnetPayment = NULL; + pnetTestnet0 = NULL; + + activePaymentNetwork = NULL; + } + + void initialize() + { + legacyTemplate = new CNetworkTemplate(); + ConstructLegacyNetworkTemplate(); + netManTestnetTemplate = new CNetworkTemplate(); + ConstructTetnet0Template(); + //only run construct networks after all templates have been made + ConstructNetworks(); + } + + void ConstructLegacyNetworkTemplate(); + + void ConstructTetnet0Template(); + + void ConstructNetworks(); + + CNetwork* getActivePaymentNetwork() + { + return activePaymentNetwork; + } + + void SetParams(const std::string& network) + { + if (network == "LEGACY") + { + activePaymentNetwork = pnetLegacy; + } + else if (network == "TESTNET0-TEMPORARY") + { + activePaymentNetwork = pnetTestnet0; + } + else + { + throw std::runtime_error(strprintf("%s: Unknown network %s.", __func__, network)); + } + return; + } +private: + CNetwork* activePaymentNetwork; + + CNetwork* pnetLegacy; + CNetwork* pnetPayment; + + CNetwork* pnetTestnet0; + + CNetworkTemplate* legacyTemplate; + CNetworkTemplate* paymentTemplate; + CNetworkTemplate* netManTestnetTemplate; + + +}; + +/// TODO : Fix this workaround that is used for RPC on command line. shuould either construct pnetMan earlier or find another way to get this value +int RPCPortFromCommandLine(); + +/** + * Looks for -regtest, -testnet and returns the appropriate BIP70 chain name. + * @return CBaseChainParams::MAX_NETWORK_TYPES if an invalid combination is given. CBaseChainParams::MAIN by default. + */ +std::string ChainNameFromCommandLine(); + + +void CheckParams(const std::string& network); + +#endif // BITCOIN_CHAINPARAMSBASE_H + diff --git a/src/networks/network.h b/src/networks/network.h new file mode 100644 index 00000000..d6bfaffa --- /dev/null +++ b/src/networks/network.h @@ -0,0 +1,54 @@ +// Copyright (c) 2017 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef NETWORK_H +#define NETWORK_H + +#include +#include +#include + +#include "chain/chainman.h" +#include "networktemplate.h" + + +/** BIP70 chain name strings */ +/* + + //ecc payment networks + LEGACY = "LEGACY", // legacy network that started the chain in 2014. will be replaced by payment network in 2018 + PAYMENT = "PAYMENT", // payment network + + //service networks + ANS = "ANS" , // Address-Name Service (DNS for addresses to usernames) + CMAP = "CMAP", // Chain Messaging Access Protocol (on chain IMAP) (where the chain is the server and daemons are the clients) + SFSP = "SFSP", // Secure File Storage Protocol (SFTP equivalent) + WEB = "WEB" , // (HTTP and HTTPS) + + /// if testnet or regtest are active, none of the service networks should be allowed to be + TESTNET = "TESTNET", // + REGTEST = "REGTEST", // + +*/ + +/** + * CNetwork defines the base parameters (shared between bitcoin-cli and bitcoind) + * of a given instance of the Bitcoin system. + */ +class CNetwork : public CNetworkTemplate +{ +public: + CNetwork(CNetworkTemplate* param_netTemplate) : CNetworkTemplate(param_netTemplate) + { + this->chainman = CChainManager(); + } + const std::string& DataDir() const { return strNetworkDataDir; } + CChainManager* getChainManager() { return &chainman; } + + /// TODO: put a check somewhere to make sure all data members have been set properly +private: + CChainManager chainman; +}; + +#endif // NETWORK_H diff --git a/src/chainparams.h b/src/networks/networktemplate.h similarity index 54% rename from src/chainparams.h rename to src/networks/networktemplate.h index c7b9b4ca..4bc1f518 100644 --- a/src/chainparams.h +++ b/src/networks/networktemplate.h @@ -1,14 +1,12 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2015 The Bitcoin Core developers +// Copyright (c) 2017 Greg Griffith and the ECC developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_CHAINPARAMS_H #define BITCOIN_CHAINPARAMS_H -#include "chainparamsbase.h" #include "consensus/params.h" -#include "primitives/block.h" +#include "chain/block.h" #include "protocol.h" #include @@ -31,7 +29,7 @@ struct CCheckpointData { * a regression test mode which is intended for private networks only. It has * minimal difficulty to ensure that blocks can be found instantly. */ -class CChainParams +class CNetworkTemplate { public: enum Base58Type { @@ -44,10 +42,32 @@ class CChainParams MAX_BASE58_TYPES }; + /// TODO: make all of the data members below this point protected and make setters for them all + + Consensus::Params consensus; + CMessageHeader::MessageStartChars pchMessageStart; + int nDefaultPort; + int nRPCPort; + long nMaxTipAge; + std::vector vSeeds; + std::vector base58Prefixes[MAX_BASE58_TYPES]; + std::string strNetworkID; + std::string strNetworkDataDir; + CBlock genesis; + bool fMiningRequiresPeers; + bool fDefaultConsistencyChecks; + bool fRequireStandard; + bool fMineBlocksOnDemand; + bool fTestnetToBeDeprecatedFieldRPC; + CCheckpointData checkpointData; + unsigned int nStakeMaxAge; + unsigned int nStakeMinAge; + + const Consensus::Params& GetConsensus() const { return consensus; } const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } - const std::vector& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } + int GetRPCPort() const { return nRPCPort; } const CBlock& GenesisBlock() const { return genesis; } /** Make miner wait to have peers to avoid wasting work */ @@ -63,50 +83,55 @@ class CChainParams bool TestnetToBeDeprecatedFieldRPC() const { return fTestnetToBeDeprecatedFieldRPC; } /** Return the BIP70 network string (main, test or regtest) */ std::string NetworkIDString() const { return strNetworkID; } + std::string NetworkDataDir() const { return strNetworkDataDir; } const std::vector& DNSSeeds() const { return vSeeds; } const std::vector& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } const CCheckpointData& Checkpoints() const { return checkpointData; } unsigned int getStakeMaxAge() const { return nStakeMaxAge; } unsigned int getStakeMinAge() const { return nStakeMinAge; } + + int getpch0() const { return pchMessageStart[0]; } + int getpch1() const { return pchMessageStart[1]; } + int getpch2() const { return pchMessageStart[2]; } + int getpch3() const { return pchMessageStart[3]; } -protected: - CChainParams() {} + CNetworkTemplate() + { - Consensus::Params consensus; - CMessageHeader::MessageStartChars pchMessageStart; - //! Raw pub key bytes for the broadcast alert signing key. - std::vector vAlertPubKey; - int nDefaultPort; - long nMaxTipAge; - std::vector vSeeds; - std::vector base58Prefixes[MAX_BASE58_TYPES]; - std::string strNetworkID; - CBlock genesis; - bool fMiningRequiresPeers; - bool fDefaultConsistencyChecks; - bool fRequireStandard; - bool fMineBlocksOnDemand; - bool fTestnetToBeDeprecatedFieldRPC; - CCheckpointData checkpointData; - unsigned int nStakeMaxAge; - unsigned int nStakeMinAge; -}; + } -/** - * Return the currently selected parameters. This won't change after app - * startup, except for unit tests. - */ -const CChainParams &Params(); + CNetworkTemplate(CNetworkTemplate* param_netTemplate) + { + this->consensus = param_netTemplate->GetConsensus(); -/** - * @returns CChainParams for the given BIP70 chain name. - */ -CChainParams& Params(const std::string& chain); + this->pchMessageStart[0] = param_netTemplate->getpch0(); + this->pchMessageStart[1] = param_netTemplate->getpch1(); + this->pchMessageStart[2] = param_netTemplate->getpch2(); + this->pchMessageStart[3] = param_netTemplate->getpch3(); -/** - * Sets the params returned by Params() to those for the given BIP70 chain name. - * @throws std::runtime_error when the chain is not supported. - */ -void SelectParams(const std::string& chain); + this->base58Prefixes[CNetworkTemplate::PUBKEY_ADDRESS] = param_netTemplate->Base58Prefix(CNetworkTemplate::PUBKEY_ADDRESS); + this->base58Prefixes[CNetworkTemplate::SCRIPT_ADDRESS] = param_netTemplate->Base58Prefix(CNetworkTemplate::SCRIPT_ADDRESS); + this->base58Prefixes[CNetworkTemplate::SECRET_KEY] = param_netTemplate->Base58Prefix(CNetworkTemplate::SECRET_KEY); + this->base58Prefixes[CNetworkTemplate::EXT_PUBLIC_KEY] = param_netTemplate->Base58Prefix(CNetworkTemplate::EXT_PUBLIC_KEY); + this->base58Prefixes[CNetworkTemplate::EXT_SECRET_KEY] = param_netTemplate->Base58Prefix(CNetworkTemplate::EXT_SECRET_KEY); + + this->nDefaultPort = param_netTemplate->GetDefaultPort(); + this->nRPCPort = param_netTemplate->GetRPCPort(); + this->nMaxTipAge = param_netTemplate->MaxTipAge(); + this->vSeeds = param_netTemplate->DNSSeeds(); + this->strNetworkID = param_netTemplate->NetworkIDString(); + this->strNetworkDataDir = param_netTemplate->NetworkDataDir(); + this->genesis = param_netTemplate->GenesisBlock(); + this->fMiningRequiresPeers = param_netTemplate->MiningRequiresPeers(); + this->fDefaultConsistencyChecks = param_netTemplate->DefaultConsistencyChecks(); + this->fRequireStandard = param_netTemplate->RequireStandard(); + this->fMineBlocksOnDemand = param_netTemplate->MineBlocksOnDemand(); + this->fTestnetToBeDeprecatedFieldRPC = param_netTemplate->TestnetToBeDeprecatedFieldRPC(); + this->checkpointData = param_netTemplate->Checkpoints(); + this->nStakeMaxAge = param_netTemplate->getStakeMaxAge(); + this->nStakeMinAge = param_netTemplate->getStakeMinAge(); + + } +}; #endif // BITCOIN_CHAINPARAMS_H diff --git a/src/noui.cpp b/src/noui.cpp index 3a773619..c21e4d85 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -6,7 +6,7 @@ #include "noui.h" #include "ui_interface.h" -#include "util.h" +#include "util/util.h" #include #include diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index a657ccf7..77119b12 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -7,10 +7,10 @@ #include "policy/policy.h" #include "amount.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include "streams.h" #include "txmempool.h" -#include "util.h" +#include "util/util.h" #include "args.h" void TxConfirmStats::Initialize(std::vector& defaultBuckets, diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 5bd8f7b0..aa794054 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -9,8 +9,8 @@ #include "main.h" #include "tinyformat.h" -#include "util.h" -#include "utilstrencodings.h" +#include "util/util.h" +#include "util/utilstrencodings.h" /** * Check transaction inputs to mitigate two @@ -65,7 +65,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason) // almost as much to process as they cost the sender in fees, because // computing signature hashes is O(ninputs*txsize). Limiting transactions // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. - unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); + unsigned int sz = GetSerializeSize(tx, SER_NETWORK, CTransaction::CURRENT_VERSION); if (sz >= MAX_STANDARD_TX_SIZE) { reason = "tx-size"; return false; diff --git a/src/pow.cpp b/src/pow.cpp index 14825269..98426676 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -6,10 +6,9 @@ #include "pow.h" #include "arith_uint256.h" -#include "chain.h" -#include "primitives/block.h" +#include "chain/chain.h" #include "uint256.h" -#include "util.h" +#include "util/util.h" #include "main.h" bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) diff --git a/src/pow.h b/src/pow.h index 73d0b391..b03d0130 100644 --- a/src/pow.h +++ b/src/pow.h @@ -7,7 +7,7 @@ #define BITCOIN_POW_H #include "consensus/params.h" -#include "blockindex.h" +#include "chain/blockindex.h" #include diff --git a/src/prevector.h b/src/prevector.h index 8992e305..c4450fc4 100644 --- a/src/prevector.h +++ b/src/prevector.h @@ -5,60 +5,91 @@ #include #include +#include +#include +#include +#include + #include #pragma pack(push, 1) -/** Implements a drop-in replacement for std::vector which stores up to N - * elements directly (without heap allocation). The types Size and Diff are - * used to store element counts, and can be any unsigned + signed type. +/** + * Implements a drop-in replacement for std::vector which stores up to N + * elements directly (without heap allocation). The types Size and Diff are used + * to store element counts, and can be any unsigned + signed type. * - * Storage layout is either: - * - Direct allocation: - * - Size _size: the number of used elements (between 0 and N) - * - T direct[N]: an array of N elements of type T - * (only the first _size are initialized). - * - Indirect allocation: - * - Size _size: the number of used elements plus N + 1 - * - Size capacity: the number of allocated elements - * - T* indirect: a pointer to an array of capacity elements of type T - * (only the first _size are initialized). + * Storage layout is either: + * - Direct allocation: + * - Size _size: the number of used elements (between 0 and N) + * - T direct[N]: an array of N elements of type T + * (only the first _size are initialized). + * - Indirect allocation: + * - Size _size: the number of used elements plus N + 1 + * - Size capacity: the number of allocated elements + * - T* indirect: a pointer to an array of capacity elements of type T + * (only the first _size are initialized). * - * The data type T must be movable by memmove/realloc(). Once we switch to C++, - * move constructors can be used instead. + * The data type T must be movable by memmove/realloc(). Once we switch to C++, + * move constructors can be used instead. */ -template +template class prevector { public: typedef Size size_type; typedef Diff difference_type; typedef T value_type; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef value_type* pointer; - typedef const value_type* const_pointer; + typedef value_type &reference; + typedef const value_type &const_reference; + typedef value_type *pointer; + typedef const value_type *const_pointer; class iterator { - T* ptr; + T *ptr; + public: typedef Diff difference_type; typedef T value_type; - typedef T* pointer; - typedef T& reference; + typedef T *pointer; + typedef T &reference; typedef std::random_access_iterator_tag iterator_category; - iterator(T* ptr_) : ptr(ptr_) {} - T& operator*() const { return *ptr; } - T* operator->() const { return ptr; } - T& operator[](size_type pos) { return ptr[pos]; } - const T& operator[](size_type pos) const { return ptr[pos]; } - iterator& operator++() { ptr++; return *this; } - iterator& operator--() { ptr--; return *this; } - iterator operator++(int) { iterator copy(*this); ++(*this); return copy; } - iterator operator--(int) { iterator copy(*this); --(*this); return copy; } - difference_type friend operator-(iterator a, iterator b) { return (&(*a) - &(*b)); } + iterator() : ptr(nullptr) {} + iterator(T *ptr_) : ptr(ptr_) {} + T &operator*() const { return *ptr; } + T *operator->() const { return ptr; } + T &operator[](size_type pos) { return ptr[pos]; } + const T &operator[](size_type pos) const { return ptr[pos]; } + iterator &operator++() { + ptr++; + return *this; + } + iterator &operator--() { + ptr--; + return *this; + } + iterator operator++(int) { + iterator copy(*this); + ++(*this); + return copy; + } + iterator operator--(int) { + iterator copy(*this); + --(*this); + return copy; + } + difference_type friend operator-(iterator a, iterator b) { + return (&(*a) - &(*b)); + } iterator operator+(size_type n) { return iterator(ptr + n); } - iterator& operator+=(size_type n) { ptr += n; return *this; } + iterator &operator+=(size_type n) { + ptr += n; + return *this; + } iterator operator-(size_type n) { return iterator(ptr - n); } - iterator& operator-=(size_type n) { ptr -= n; return *this; } + iterator &operator-=(size_type n) { + ptr -= n; + return *this; + } bool operator==(iterator x) const { return ptr == x.ptr; } bool operator!=(iterator x) const { return ptr != x.ptr; } bool operator>=(iterator x) const { return ptr >= x.ptr; } @@ -68,48 +99,92 @@ class prevector { }; class reverse_iterator { - T* ptr; + T *ptr; + public: typedef Diff difference_type; typedef T value_type; - typedef T* pointer; - typedef T& reference; + typedef T *pointer; + typedef T &reference; typedef std::bidirectional_iterator_tag iterator_category; - reverse_iterator(T* ptr_) : ptr(ptr_) {} - T& operator*() { return *ptr; } - const T& operator*() const { return *ptr; } - T* operator->() { return ptr; } - const T* operator->() const { return ptr; } - reverse_iterator& operator--() { ptr++; return *this; } - reverse_iterator& operator++() { ptr--; return *this; } - reverse_iterator operator++(int) { reverse_iterator copy(*this); ++(*this); return copy; } - reverse_iterator operator--(int) { reverse_iterator copy(*this); --(*this); return copy; } + reverse_iterator() : ptr(nullptr) {} + reverse_iterator(T *ptr_) : ptr(ptr_) {} + T &operator*() { return *ptr; } + const T &operator*() const { return *ptr; } + T *operator->() { return ptr; } + const T *operator->() const { return ptr; } + reverse_iterator &operator--() { + ptr++; + return *this; + } + reverse_iterator &operator++() { + ptr--; + return *this; + } + reverse_iterator operator++(int) { + reverse_iterator copy(*this); + ++(*this); + return copy; + } + reverse_iterator operator--(int) { + reverse_iterator copy(*this); + --(*this); + return copy; + } bool operator==(reverse_iterator x) const { return ptr == x.ptr; } bool operator!=(reverse_iterator x) const { return ptr != x.ptr; } }; class const_iterator { - const T* ptr; + const T *ptr; + public: typedef Diff difference_type; typedef const T value_type; - typedef const T* pointer; - typedef const T& reference; + typedef const T *pointer; + typedef const T &reference; typedef std::random_access_iterator_tag iterator_category; - const_iterator(const T* ptr_) : ptr(ptr_) {} + const_iterator() : ptr(nullptr) {} + const_iterator(const T *ptr_) : ptr(ptr_) {} const_iterator(iterator x) : ptr(&(*x)) {} - const T& operator*() const { return *ptr; } - const T* operator->() const { return ptr; } - const T& operator[](size_type pos) const { return ptr[pos]; } - const_iterator& operator++() { ptr++; return *this; } - const_iterator& operator--() { ptr--; return *this; } - const_iterator operator++(int) { const_iterator copy(*this); ++(*this); return copy; } - const_iterator operator--(int) { const_iterator copy(*this); --(*this); return copy; } - difference_type friend operator-(const_iterator a, const_iterator b) { return (&(*a) - &(*b)); } - const_iterator operator+(size_type n) { return const_iterator(ptr + n); } - const_iterator& operator+=(size_type n) { ptr += n; return *this; } - const_iterator operator-(size_type n) { return const_iterator(ptr - n); } - const_iterator& operator-=(size_type n) { ptr -= n; return *this; } + const T &operator*() const { return *ptr; } + const T *operator->() const { return ptr; } + const T &operator[](size_type pos) const { return ptr[pos]; } + const_iterator &operator++() { + ptr++; + return *this; + } + const_iterator &operator--() { + ptr--; + return *this; + } + const_iterator operator++(int) { + const_iterator copy(*this); + ++(*this); + return copy; + } + const_iterator operator--(int) { + const_iterator copy(*this); + --(*this); + return copy; + } + difference_type friend operator-(const_iterator a, const_iterator b) { + return (&(*a) - &(*b)); + } + const_iterator operator+(size_type n) { + return const_iterator(ptr + n); + } + const_iterator &operator+=(size_type n) { + ptr += n; + return *this; + } + const_iterator operator-(size_type n) { + return const_iterator(ptr - n); + } + const_iterator &operator-=(size_type n) { + ptr -= n; + return *this; + } bool operator==(const_iterator x) const { return ptr == x.ptr; } bool operator!=(const_iterator x) const { return ptr != x.ptr; } bool operator>=(const_iterator x) const { return ptr >= x.ptr; } @@ -119,21 +194,37 @@ class prevector { }; class const_reverse_iterator { - const T* ptr; + const T *ptr; + public: typedef Diff difference_type; typedef const T value_type; - typedef const T* pointer; - typedef const T& reference; + typedef const T *pointer; + typedef const T &reference; typedef std::bidirectional_iterator_tag iterator_category; - const_reverse_iterator(T* ptr_) : ptr(ptr_) {} + const_reverse_iterator() : ptr(nullptr) {} + const_reverse_iterator(T *ptr_) : ptr(ptr_) {} const_reverse_iterator(reverse_iterator x) : ptr(&(*x)) {} - const T& operator*() const { return *ptr; } - const T* operator->() const { return ptr; } - const_reverse_iterator& operator--() { ptr++; return *this; } - const_reverse_iterator& operator++() { ptr--; return *this; } - const_reverse_iterator operator++(int) { const_reverse_iterator copy(*this); ++(*this); return copy; } - const_reverse_iterator operator--(int) { const_reverse_iterator copy(*this); --(*this); return copy; } + const T &operator*() const { return *ptr; } + const T *operator->() const { return ptr; } + const_reverse_iterator &operator--() { + ptr++; + return *this; + } + const_reverse_iterator &operator++() { + ptr--; + return *this; + } + const_reverse_iterator operator++(int) { + const_reverse_iterator copy(*this); + ++(*this); + return copy; + } + const_reverse_iterator operator--(int) { + const_reverse_iterator copy(*this); + --(*this); + return copy; + } bool operator==(const_reverse_iterator x) const { return ptr == x.ptr; } bool operator!=(const_reverse_iterator x) const { return ptr != x.ptr; } }; @@ -144,34 +235,51 @@ class prevector { char direct[sizeof(T) * N]; struct { size_type capacity; - char* indirect; + char *indirect; }; } _union; - T* direct_ptr(difference_type pos) { return reinterpret_cast(_union.direct) + pos; } - const T* direct_ptr(difference_type pos) const { return reinterpret_cast(_union.direct) + pos; } - T* indirect_ptr(difference_type pos) { return reinterpret_cast(_union.indirect) + pos; } - const T* indirect_ptr(difference_type pos) const { return reinterpret_cast(_union.indirect) + pos; } + T *direct_ptr(difference_type pos) { + return reinterpret_cast(_union.direct) + pos; + } + const T *direct_ptr(difference_type pos) const { + return reinterpret_cast(_union.direct) + pos; + } + T *indirect_ptr(difference_type pos) { + return reinterpret_cast(_union.indirect) + pos; + } + const T *indirect_ptr(difference_type pos) const { + return reinterpret_cast(_union.indirect) + pos; + } bool is_direct() const { return _size <= N; } void change_capacity(size_type new_capacity) { if (new_capacity <= N) { if (!is_direct()) { - T* indirect = indirect_ptr(0); - T* src = indirect; - T* dst = direct_ptr(0); + T *indirect = indirect_ptr(0); + T *src = indirect; + T *dst = direct_ptr(0); memcpy(dst, src, size() * sizeof(T)); free(indirect); _size -= N + 1; } } else { if (!is_direct()) { - _union.indirect = static_cast(realloc(_union.indirect, ((size_t)sizeof(T)) * new_capacity)); + // FIXME: Because malloc/realloc here won't call new_handler if + // allocation fails, assert success. These should instead use an + // allocator or new/delete so that handlers are called as + // necessary, but performance would be slightly degraded by + // doing so. + _union.indirect = static_cast(realloc( + _union.indirect, ((size_t)sizeof(T)) * new_capacity)); + assert(_union.indirect); _union.capacity = new_capacity; } else { - char* new_indirect = static_cast(malloc(((size_t)sizeof(T)) * new_capacity)); - T* src = direct_ptr(0); - T* dst = reinterpret_cast(new_indirect); + char *new_indirect = static_cast( + malloc(((size_t)sizeof(T)) * new_capacity)); + assert(new_indirect); + T *src = direct_ptr(0); + T *dst = reinterpret_cast(new_indirect); memcpy(dst, src, size() * sizeof(T)); _union.indirect = new_indirect; _union.capacity = new_capacity; @@ -180,22 +288,26 @@ class prevector { } } - T* item_ptr(difference_type pos) { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } - const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } + T *item_ptr(difference_type pos) { + return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); + } + const T *item_ptr(difference_type pos) const { + return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); + } public: - void assign(size_type n, const T& val) { + void assign(size_type n, const T &val) { clear(); if (capacity() < n) { change_capacity(n); } while (size() < n) { _size++; - new(static_cast(item_ptr(size() - 1))) T(val); + new (static_cast(item_ptr(size() - 1))) T(val); } } - template + template void assign(InputIterator first, InputIterator last) { size_type n = last - first; clear(); @@ -204,47 +316,47 @@ class prevector { } while (first != last) { _size++; - new(static_cast(item_ptr(size() - 1))) T(*first); + new (static_cast(item_ptr(size() - 1))) T(*first); ++first; } } prevector() : _size(0) {} - explicit prevector(size_type n) : _size(0) { - resize(n); - } + explicit prevector(size_type n) : _size(0) { resize(n); } - explicit prevector(size_type n, const T& val = T()) : _size(0) { + explicit prevector(size_type n, const T &val = T()) : _size(0) { change_capacity(n); while (size() < n) { _size++; - new(static_cast(item_ptr(size() - 1))) T(val); + new (static_cast(item_ptr(size() - 1))) T(val); } } - template + template prevector(InputIterator first, InputIterator last) : _size(0) { size_type n = last - first; change_capacity(n); while (first != last) { _size++; - new(static_cast(item_ptr(size() - 1))) T(*first); + new (static_cast(item_ptr(size() - 1))) T(*first); ++first; } } - prevector(const prevector& other) : _size(0) { + prevector(const prevector &other) : _size(0) { change_capacity(other.size()); const_iterator it = other.begin(); while (it != other.end()) { _size++; - new(static_cast(item_ptr(size() - 1))) T(*it); + new (static_cast(item_ptr(size() - 1))) T(*it); ++it; } } - prevector& operator=(const prevector& other) { + prevector(prevector &&other) : _size(0) { swap(other); } + + prevector &operator=(const prevector &other) { if (&other == this) { return *this; } @@ -253,19 +365,20 @@ class prevector { const_iterator it = other.begin(); while (it != other.end()) { _size++; - new(static_cast(item_ptr(size() - 1))) T(*it); + new (static_cast(item_ptr(size() - 1))) T(*it); ++it; } return *this; } - size_type size() const { - return is_direct() ? _size : _size - N - 1; + prevector &operator=(prevector &&other) { + swap(other); + return *this; } - bool empty() const { - return size() == 0; - } + size_type size() const { return is_direct() ? _size : _size - N - 1; } + + bool empty() const { return size() == 0; } iterator begin() { return iterator(item_ptr(0)); } const_iterator begin() const { return const_iterator(item_ptr(0)); } @@ -273,9 +386,13 @@ class prevector { const_iterator end() const { return const_iterator(item_ptr(size())); } reverse_iterator rbegin() { return reverse_iterator(item_ptr(size() - 1)); } - const_reverse_iterator rbegin() const { return const_reverse_iterator(item_ptr(size() - 1)); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(item_ptr(size() - 1)); + } reverse_iterator rend() { return reverse_iterator(item_ptr(-1)); } - const_reverse_iterator rend() const { return const_reverse_iterator(item_ptr(-1)); } + const_reverse_iterator rend() const { + return const_reverse_iterator(item_ptr(-1)); + } size_t capacity() const { if (is_direct()) { @@ -285,25 +402,20 @@ class prevector { } } - T& operator[](size_type pos) { - return *item_ptr(pos); - } + T &operator[](size_type pos) { return *item_ptr(pos); } - const T& operator[](size_type pos) const { - return *item_ptr(pos); - } + const T &operator[](size_type pos) const { return *item_ptr(pos); } void resize(size_type new_size) { - while (size() > new_size) { - item_ptr(size() - 1)->~T(); - _size--; + if (size() > new_size) { + erase(item_ptr(new_size), end()); } if (new_size > capacity()) { change_capacity(new_size); } while (size() < new_size) { _size++; - new(static_cast(item_ptr(size() - 1))) T(); + new (static_cast(item_ptr(size() - 1))) T(); } } @@ -313,15 +425,11 @@ class prevector { } } - void shrink_to_fit() { - change_capacity(size()); - } + void shrink_to_fit() { change_capacity(size()); } - void clear() { - resize(0); - } + void clear() { resize(0); } - iterator insert(iterator pos, const T& value) { + iterator insert(iterator pos, const T &value) { size_type p = pos - begin(); size_type new_size = size() + 1; if (capacity() < new_size) { @@ -329,11 +437,11 @@ class prevector { } memmove(item_ptr(p + 1), item_ptr(p), (size() - p) * sizeof(T)); _size++; - new(static_cast(item_ptr(p))) T(value); + new (static_cast(item_ptr(p))) T(value); return iterator(item_ptr(p)); } - void insert(iterator pos, size_type count, const T& value) { + void insert(iterator pos, size_type count, const T &value) { size_type p = pos - begin(); size_type new_size = size() + count; if (capacity() < new_size) { @@ -342,11 +450,11 @@ class prevector { memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T)); _size += count; for (size_type i = 0; i < count; i++) { - new(static_cast(item_ptr(p + i))) T(value); + new (static_cast(item_ptr(p + i))) T(value); } } - template + template void insert(iterator pos, InputIterator first, InputIterator last) { size_type p = pos - begin(); difference_type count = last - first; @@ -357,67 +465,47 @@ class prevector { memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T)); _size += count; while (first != last) { - new(static_cast(item_ptr(p))) T(*first); + new (static_cast(item_ptr(p))) T(*first); ++p; ++first; } } - iterator erase(iterator pos) { - (*pos).~T(); - memmove(&(*pos), &(*pos) + 1, ((char*)&(*end())) - ((char*)(1 + &(*pos)))); - _size--; - return pos; - } + iterator erase(iterator pos) { return erase(pos, pos + 1); } iterator erase(iterator first, iterator last) { iterator p = first; - char* endp = (char*)&(*end()); + char *endp = (char *)&(*end()); while (p != last) { (*p).~T(); _size--; ++p; } - memmove(&(*first), &(*last), endp - ((char*)(&(*last)))); + memmove(&(*first), &(*last), endp - ((char *)(&(*last)))); return first; } - void push_back(const T& value) { + void push_back(const T &value) { size_type new_size = size() + 1; if (capacity() < new_size) { change_capacity(new_size + (new_size >> 1)); } - new(item_ptr(size())) T(value); + new (item_ptr(size())) T(value); _size++; } - void pop_back() { - _size--; - } + void pop_back() { erase(end() - 1, end()); } - T& front() { - return *item_ptr(0); - } + T &front() { return *item_ptr(0); } - const T& front() const { - return *item_ptr(0); - } + const T &front() const { return *item_ptr(0); } - T& back() { - return *item_ptr(size() - 1); - } + T &back() { return *item_ptr(size() - 1); } - const T& back() const { - return *item_ptr(size() - 1); - } + const T &back() const { return *item_ptr(size() - 1); } - void swap(prevector& other) { - if (_size & other._size & 1) { - std::swap(_union.capacity, other._union.capacity); - std::swap(_union.indirect, other._union.indirect); - } else { - std::swap(_union, other._union); - } + void swap(prevector &other) { + std::swap(_union, other._union); std::swap(_size, other._size); } @@ -425,11 +513,11 @@ class prevector { clear(); if (!is_direct()) { free(_union.indirect); - _union.indirect = NULL; + _union.indirect = nullptr; } } - bool operator==(const prevector& other) const { + bool operator==(const prevector &other) const { if (other.size() != size()) { return false; } @@ -446,11 +534,11 @@ class prevector { return true; } - bool operator!=(const prevector& other) const { + bool operator!=(const prevector &other) const { return !(*this == other); } - bool operator<(const prevector& other) const { + bool operator<(const prevector &other) const { if (size() < other.size()) { return true; } @@ -480,7 +568,12 @@ class prevector { return ((size_t)(sizeof(T))) * _union.capacity; } } + + value_type *data() { return item_ptr(0); } + + const value_type *data() const { return item_ptr(0); } }; #pragma pack(pop) + #endif diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h deleted file mode 100644 index e0f06499..00000000 --- a/src/primitives/transaction.h +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright (c) 2009-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_PRIMITIVES_TRANSACTION_H -#define BITCOIN_PRIMITIVES_TRANSACTION_H - -#include "amount.h" -#include "script/script.h" -#include "serialize.h" -#include "uint256.h" - -class CBlockTreeDB; - -/** An outpoint - a combination of a transaction hash and an index n into its vout */ -class COutPoint -{ -public: - uint256 hash; - uint32_t n; - - COutPoint() { SetNull(); } - COutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; } - - ADD_SERIALIZE_METHODS - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(hash); - READWRITE(n); - } - - void SetNull() { hash.SetNull(); n = (uint32_t) -1; } - bool IsNull() const { return (hash.IsNull() && n == (uint32_t) -1); } - - friend bool operator<(const COutPoint& a, const COutPoint& b) - { - return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n)); - } - - friend bool operator==(const COutPoint& a, const COutPoint& b) - { - return (a.hash == b.hash && a.n == b.n); - } - - friend bool operator!=(const COutPoint& a, const COutPoint& b) - { - return !(a == b); - } - - std::string ToString() const; -}; - -/** An input of a transaction. It contains the location of the previous - * transaction's output that it claims and a signature that matches the - * output's public key. - */ -class CTxIn -{ -public: - COutPoint prevout; - CScript scriptSig; - uint32_t nSequence; - - /* Setting nSequence to this value for every input in a transaction - * disables nLockTime. */ - static const uint32_t SEQUENCE_FINAL = 0xffffffff; - - /* Below flags apply in the context of BIP 68*/ - /* If this flag set, CTxIn::nSequence is NOT interpreted as a - * relative lock-time. */ - static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31); - - /* If CTxIn::nSequence encodes a relative lock-time and this flag - * is set, the relative lock-time has units of 512 seconds, - * otherwise it specifies blocks with a granularity of 1. */ - static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22); - - /* If CTxIn::nSequence encodes a relative lock-time, this mask is - * applied to extract that lock-time from the sequence field. */ - static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff; - - /* In order to use the same number of bits to encode roughly the - * same wall-clock duration, and because blocks are naturally - * limited to occur every 600s on average, the minimum granularity - * for time-based relative lock-time is fixed at 512 seconds. - * Converting from CTxIn::nSequence to seconds is performed by - * multiplying by 512 = 2^9, or equivalently shifting up by - * 9 bits. */ - static const int SEQUENCE_LOCKTIME_GRANULARITY = 9; - - CTxIn() - { - nSequence = SEQUENCE_FINAL; - } - - explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL); - CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL); - - ADD_SERIALIZE_METHODS - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(prevout); - READWRITE(*(CScriptBase*)(&scriptSig)); - READWRITE(nSequence); - } - - friend bool operator==(const CTxIn& a, const CTxIn& b) - { - return (a.prevout == b.prevout && - a.scriptSig == b.scriptSig && - a.nSequence == b.nSequence); - } - - friend bool operator!=(const CTxIn& a, const CTxIn& b) - { - return !(a == b); - } - - bool IsFinal() const - { - return (nSequence == std::numeric_limits::max()); - } - - - std::string ToString() const; -}; - -/** An output of a transaction. It contains the public key that the next input - * must be able to sign with to claim it. - */ -class CTxOut -{ -public: - CAmount nValue; - CScript scriptPubKey; - - CTxOut() - { - SetNull(); - } - - CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn); - - ADD_SERIALIZE_METHODS - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(nValue); - READWRITE(*(CScriptBase*)(&scriptPubKey)); - } - - void SetNull() - { - nValue = -1; - scriptPubKey.clear(); - } - - bool IsNull() const - { - return (nValue == -1); - } - - void SetEmpty() - { - nValue = 0; - scriptPubKey.clear(); - } - - bool IsEmpty() const - { - return (nValue == 0 && scriptPubKey.empty()); - } - - uint256 GetHash() const; - - CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const - { - // "Dust" is defined in terms of CTransaction::minRelayTxFee, - // which has units satoshis-per-kilobyte. - // If you'd pay more than 1/3 in fees - // to spend something, then we consider it dust. - // A typical spendable txout is 34 bytes big, and will - // need a CTxIn of at least 148 bytes to spend: - // so dust is a spendable txout less than - // 546*minRelayTxFee/1000 (in satoshis) - if (scriptPubKey.IsUnspendable()) - return 0; - - size_t nSize = GetSerializeSize(SER_DISK,0)+148u; - return 3*minRelayTxFee.GetFee(nSize); - } - - bool IsDust(const CFeeRate &minRelayTxFee) const - { - return (nValue < GetDustThreshold(minRelayTxFee)); - } - - friend bool operator==(const CTxOut& a, const CTxOut& b) - { - return (a.nValue == b.nValue && - a.scriptPubKey == b.scriptPubKey); - } - - friend bool operator!=(const CTxOut& a, const CTxOut& b) - { - return !(a == b); - } - - std::string ToString() const; -}; - - -/** The basic transaction that is broadcasted on the network and contained in - * blocks. A transaction can contain multiple inputs and outputs. - */ -class CTransaction -{ -private: - /** Memory only. */ - const uint256 hash; - void UpdateHash() const; - -public: - // Default transaction version. - static const int32_t CURRENT_VERSION=1; - - // Changing the default transaction version requires a two step process: first - // adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date - // bumping the default CURRENT_VERSION at which point both CURRENT_VERSION and - // MAX_STANDARD_VERSION will be equal. - static const int32_t MAX_STANDARD_VERSION=2; - - // The local variables are made const to prevent unintended modification - // without updating the cached hash value. However, CTransaction is not - // actually immutable; deserialization and assignment are implemented, - // and bypass the constness. This is safe, as they update the entire - // structure, including the hash. - int32_t nVersion; - unsigned int nTime; - std::vector vin; - std::vector vout; - uint32_t nLockTime; - - /** Construct a CTransaction that qualifies as IsNull() */ - CTransaction(); - - /** Convert a CTransaction into a CTransaction. */ - CTransaction(const CTransaction &tx); - - CTransaction& operator=(const CTransaction& tx); - - ADD_SERIALIZE_METHODS - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(*const_cast(&this->nVersion)); - nVersion = this->nVersion; - READWRITE(*const_cast(&this->nTime)); - READWRITE(*const_cast*>(&vin)); - READWRITE(*const_cast*>(&vout)); - READWRITE(*const_cast(&nLockTime)); - if (ser_action.ForRead()) - UpdateHash(); - } - - bool IsNull() const { - return vin.empty() && vout.empty(); - } - - uint256 GetHash() const; - - // Return sum of txouts. - CAmount GetValueOut() const; - // GetValueIn() is a method on CCoinsViewCache, because - // inputs must be known to compute value in. - - // Compute priority, given priority of inputs and (optionally) tx size - double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const; - - // Compute modified tx size for priority calculation (optionally given tx size) - unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const; - - bool IsCoinBase() const - { - return (vin.size() == 1 && vin[0].prevout.IsNull()); - } - - bool IsCoinStake() const - { - // ppcoin: the coin stake transaction is marked with the first output empty - return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty()); - } - - bool IsFinal(int nBlockHeight=0, int64_t nBlockTime=0) const; - - friend bool operator==(const CTransaction& a, const CTransaction& b) - { - return a.hash == b.hash; - } - - friend bool operator!=(const CTransaction& a, const CTransaction& b) - { - return a.hash != b.hash; - } - std::string ToString() const; - int64_t GetMinFee(unsigned int nBlockSize=1, unsigned int nBytes = 0) const; - bool GetCoinAge(uint64_t& nCoinAge) const; // ppcoin: get transaction coin age - uint64_t GetCoinAge(uint64_t nCoinAge, bool byValue) const; -}; - -#endif // BITCOIN_PRIMITIVES_TRANSACTION_H diff --git a/src/processblock.cpp b/src/processblock.cpp index f811a876..f063ce0f 100644 --- a/src/processblock.cpp +++ b/src/processblock.cpp @@ -1,20 +1,25 @@ +#include +#include + + +#include "checkqueue.h" #include "processblock.h" #include "messages.h" -#include "util.h" +#include "util/util.h" #include "args.h" #include "main.h" -#include "checkpoints.h" +#include "chain/checkpoints.h" #include "ui_interface.h" #include "validationinterface.h" #include "init.h" #include "txmempool.h" -#include "chainparams.h" +#include "networks/networktemplate.h" +#include "networks/netman.h" #include "net.h" #include "policy/policy.h" - -#include -#include - +#include "processheader.h" +#include "undo.h" +#include "kernel.h" bool fLargeWorkForkFound = false; @@ -46,8 +51,68 @@ class WarningBitsConditionChecker : public AbstractThresholdConditionChecker } }; +/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */ +bool AcceptBlock(const CBlock& block, CValidationState& state, const CNetworkTemplate& chainparams, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) +{ + AssertLockHeld(cs_main); + + CBlockIndex *&pindex = *ppindex; -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp, BlockOrigin origin) + if (!AcceptBlockHeader(block, state, chainparams, &pindex)) + return false; + + // Try to process all requested blocks that we don't have, but only + // process an unrequested block if it's new and has enough work to + // advance our tip, and isn't too many blocks ahead. + bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA; + bool fHasMoreWork = (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip() ? pindex->nChainWork > pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nChainWork : true); + // Blocks that are too out-of-order needlessly limit the effectiveness of + // pruning, because pruning will not delete block files that contain any + // blocks which are too close in height to the tip. Apply this test + // regardless of whether pruning is enabled; it should generally be safe to + // not process unrequested blocks. + bool fTooFarAhead = (pindex->nHeight > int(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() + MIN_BLOCKS_TO_KEEP)); + + // TODO: deal better with return value and error conditions for duplicate + // and unrequested blocks. + if (fAlreadyHave) return true; + if (!fRequested) { // If we didn't ask for it: + if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned + if (!fHasMoreWork) return true; // Don't process less-work chains + if (fTooFarAhead) return true; // Block height is too high + } + + if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) { + if (state.IsInvalid() && !state.CorruptionPossible()) { + pindex->nStatus |= BLOCK_FAILED_VALID; + setDirtyBlockIndex.insert(pindex); + } + return false; + } + + int nHeight = pindex->nHeight; + + // Write block to history file + try { + unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); + CDiskBlockPos blockPos; + if (dbp != NULL) + blockPos = *dbp; + if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL)) + return error("AcceptBlock(): FindBlockPos failed"); + if (dbp == NULL) + if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) + AbortNode(state, "Failed to write block"); + if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) + return error("AcceptBlock(): ReceivedBlockTransactions failed"); + } catch (const std::runtime_error& e) { + return AbortNode(state, std::string("System error: ") + e.what()); + } + + return true; +} + +bool ProcessNewBlock(CValidationState& state, const CNetworkTemplate& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp, BlockOrigin origin) { // Preliminary checks bool checked = CheckBlock(*pblock, state); @@ -80,26 +145,26 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c /** Update chainActive and related internal data structures. */ void UpdateTip(CBlockIndex *pindexNew) { - const CChainParams& chainParams = Params(); - chainActive.SetTip(pindexNew); + const CNetworkTemplate& chainParams = pnetMan->getActivePaymentNetwork(); + pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.SetTip(pindexNew); // New best block nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__, - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); + pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash().ToString(), pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height(), log(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nChainTx), + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockTime()), + Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()), pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->GetCacheSize()); cvBlockChange.notify_all(); // Check the version of the last 100 blocks to see if we need to upgrade: static bool fWarned = false; - if (!IsInitialBlockDownload()) + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload()) { int nUpgraded = 0; - const CBlockIndex* pindex = chainActive.Tip(); + const CBlockIndex* pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { WarningBitsConditionChecker checker(bit); ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]); @@ -137,7 +202,7 @@ void UpdateTip(CBlockIndex *pindexNew) { /** Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */ bool DisconnectTip(CValidationState& state, const Consensus::Params& consensusParams) { - CBlockIndex *pindexDelete = chainActive.Tip(); + CBlockIndex *pindexDelete = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); assert(pindexDelete); // Read block from disk. CBlock block; @@ -146,7 +211,7 @@ bool DisconnectTip(CValidationState& state, const Consensus::Params& consensusPa // Apply the block atomically to the chain state. int64_t nStart = GetTimeMicros(); { - CCoinsViewCache view(pcoinsTip); + CCoinsViewCache view(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get()); if (!DisconnectBlock(block, state, pindexDelete, view)) return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); assert(view.Flush()); @@ -195,9 +260,9 @@ static int64_t nTimeTotal = 0; * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock * corresponding to pindexNew, to bypass loading it again from disk. */ -bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock, BlockOrigin origin) +bool ConnectTip(CValidationState& state, const CNetworkTemplate& chainparams, CBlockIndex* pindexNew, const CBlock* pblock, BlockOrigin origin) { - assert(pindexNew->pprev == chainActive.Tip()); + assert(pindexNew->pprev == pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()); // Read block from disk. int64_t nTime1 = GetTimeMicros(); CBlock block; @@ -211,7 +276,7 @@ bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlock int64_t nTime3; LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); { - CCoinsViewCache view(pcoinsTip); + CCoinsViewCache view(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get()); bool rv = ConnectBlock(*pblock, state, pindexNew, view); GetMainSignals().BlockChecked(*pblock, state); if (!rv) @@ -221,7 +286,7 @@ bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlock InvalidBlockFound(pindexNew, state); if(origin == GENERATED) { - pindexBestHeader = chainActive.Tip(); + pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); } } return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); @@ -240,7 +305,7 @@ bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlock LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); // Remove conflicting transactions from the mempool. std::list txConflicted; - mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload()); + mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload()); // Update chainActive & related variables. UpdateTip(pindexNew); // Tell wallet about transactions that went from mempool @@ -265,15 +330,15 @@ void CheckForkWarningConditions() AssertLockHeld(cs_main); // Before we get past initial download, we cannot reliably alert about forks // (we assume we don't get stuck on a fork before the last checkpoint) - if (IsInitialBlockDownload()) + if (pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload()) return; // If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it) // of our head, drop it - if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72) + if (pindexBestForkTip && pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindexBestForkTip->nHeight >= 72) pindexBestForkTip = NULL; - if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6))) + if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nChainWork + (GetBlockProof(*pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()) * 6))) { if (!fLargeWorkForkFound && pindexBestForkBase) { @@ -305,7 +370,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) AssertLockHeld(cs_main); // If we are on a fork that is sufficiently large, set a warning flag CBlockIndex* pfork = pindexNewForkTip; - CBlockIndex* plonger = chainActive.Tip(); + CBlockIndex* plonger = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); while (pfork && pfork != plonger) { while (plonger && plonger->nHeight > pfork->nHeight) @@ -324,7 +389,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) // the 7-block condition and from this always have the most-likely-to-cause-warning fork if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) && pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) && - chainActive.Height() - pindexNewForkTip->nHeight < 72) + pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindexNewForkTip->nHeight < 72) { pindexBestForkTip = pindexNewForkTip; pindexBestForkBase = pfork; @@ -337,12 +402,12 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) * Try to make some progress towards making pindexMostWork the active block. * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. */ - bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, BlockOrigin origin) + bool ActivateBestChainStep(CValidationState& state, const CNetworkTemplate& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, BlockOrigin origin) { AssertLockHeld(cs_main); bool fInvalidFound = false; - const CBlockIndex *pindexOldTip = chainActive.Tip(); - const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); + const CBlockIndex *pindexOldTip = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); + const CBlockIndex *pindexFork = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.FindFork(pindexMostWork); /// temporary security measure against large chain attacks, reorging this many blocks should not occur naturally. a real solution should be implemented if(origin != LOADED && pindexOldTip && pindexFork && pindexOldTip->nHeight >= pindexFork->nHeight + COINBASE_MATURITY) @@ -354,7 +419,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) // Disconnect active blocks which are no longer in the best chain. bool fBlocksDisconnected = false; - while (chainActive.Tip() && chainActive.Tip() != pindexFork) { + while (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip() && pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip() != pindexFork) { if (!DisconnectTip(state, chainparams.GetConsensus())) return false; fBlocksDisconnected = true; @@ -402,7 +467,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) else { PruneBlockIndexCandidates(); - if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) { + if (!pindexOldTip || pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) { // We're in a better position than we were. Return temporarily to release the lock. fContinue = false; break; @@ -412,10 +477,10 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) } if (fBlocksDisconnected) { - mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); + mempool.removeForReorg(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get(), pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); } - mempool.check(pcoinsTip); + mempool.check(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get()); // Callbacks/notifications for a new best chain. if (fInvalidFound) @@ -431,7 +496,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) * or an activated best chain. pblock is either NULL or a pointer to a block * that is already loaded (to avoid loading it again from disk). */ -bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, BlockOrigin origin, const CBlock *pblock) { +bool ActivateBestChain(CValidationState &state, const CNetworkTemplate& chainparams, BlockOrigin origin, const CBlock *pblock) { CBlockIndex *pindexMostWork = NULL; do { boost::this_thread::interruption_point(); @@ -443,19 +508,19 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, bool fInitialDownload; { LOCK(cs_main); - CBlockIndex *pindexOldTip = chainActive.Tip(); + CBlockIndex *pindexOldTip = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); pindexMostWork = FindMostWorkChain(); // Whether we have anything to do at all. - if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) + if (pindexMostWork == NULL || pindexMostWork == pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()) return true; if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL, origin)) return false; - pindexNewTip = chainActive.Tip(); - pindexFork = chainActive.FindFork(pindexOldTip); - fInitialDownload = IsInitialBlockDownload(); + pindexNewTip = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); + pindexFork = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.FindFork(pindexOldTip); + fInitialDownload = pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload(); } // When we reach this point, we switched to a new tip (stored in pindexNewTip). @@ -485,7 +550,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, { LOCK(cs_vNodes); for (auto* pnode: vNodes) { - if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) { + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) { BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) { pnode->PushBlockHash(hash); } @@ -498,7 +563,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, } } } - } while(pindexMostWork != chainActive.Tip()); + } while(pindexMostWork != pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()); CheckBlockIndex(chainparams.GetConsensus()); // Write changes periodically to disk, after relay. @@ -521,18 +586,18 @@ void CheckBlockIndex(const Consensus::Params& consensusParams) // During a reindex, we read the genesis block and call CheckBlockIndex before ActivateBestChain, // so we have the genesis block in mapBlockIndex but no active chain. (A few of the tests when // iterating the block tree require that chainActive has been initialized.) - if (chainActive.Height() < 0) { - assert(mapBlockIndex.size() <= 1); + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() < 0) { + assert(pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.size() <= 1); return; } // Build forward-pointing map of the entire block tree. std::multimap forward; - for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) { + for (BlockMap::iterator it = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.begin(); it != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end(); it++) { forward.insert(std::make_pair(it->second->pprev, it->second)); } - assert(forward.size() == mapBlockIndex.size()); + assert(forward.size() == pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.size()); std::pair::iterator,std::multimap::iterator> rangeGenesis = forward.equal_range(NULL); CBlockIndex *pindex = rangeGenesis.first->second; @@ -565,7 +630,7 @@ void CheckBlockIndex(const Consensus::Params& consensusParams) if (pindex->pprev == NULL) { // Genesis block checks. assert(pindex->GetBlockHash() == consensusParams.hashGenesisBlock); // Genesis block's hash must match. - assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block. + assert(pindex == pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Genesis()); // The current active chain's genesis block must be this block. } if (pindex->nChainTx == 0) assert(pindex->nSequenceId == 0); // nSequenceId can't be set for blocks that aren't linked // VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred). @@ -591,13 +656,13 @@ void CheckBlockIndex(const Consensus::Params& consensusParams) // Checks for not-invalid blocks. assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents. } - if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && pindexFirstNeverProcessed == NULL) { + if (!CBlockIndexWorkComparator()(pindex, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()) && pindexFirstNeverProcessed == NULL) { if (pindexFirstInvalid == NULL) { // If this block sorts at least as good as the current tip and // is valid and we have all data for its parents, it must be in // setBlockIndexCandidates. chainActive.Tip() must also be there // even if some data has been pruned. - if (pindexFirstMissing == NULL || pindex == chainActive.Tip()) { + if (pindexFirstMissing == NULL || pindex == pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()) { assert(setBlockIndexCandidates.count(pindex)); } // If some parent is missing, then it could be that this block was in @@ -701,7 +766,7 @@ CBlockIndex* FindMostWorkChain() // Just going until the active chain is an optimization, as we know all blocks in it are valid already. CBlockIndex *pindexTest = pindexNew; bool fInvalidAncestor = false; - while (pindexTest && !chainActive.Contains(pindexTest)) { + while (pindexTest && !pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(pindexTest)) { assert(pindexTest->nChainTx || pindexTest->nHeight == 0); // Pruned nodes may have entries in setBlockIndexCandidates for @@ -716,10 +781,14 @@ CBlockIndex* FindMostWorkChain() pindexBestInvalid = pindexNew; CBlockIndex *pindexFailed = pindexNew; // Remove the entire chain from the set. - while (pindexTest != pindexFailed) { - if (fFailedChain) { + while (pindexTest != pindexFailed) + { + if (fFailedChain) + { pindexFailed->nStatus |= BLOCK_FAILED_CHILD; - } else if (fMissingData) { + } + else if (fMissingData) + { // If we're missing data, then add back to mapBlocksUnlinked, // so that if the block arrives in the future we can try adding // to setBlockIndexCandidates again. @@ -735,7 +804,9 @@ CBlockIndex* FindMostWorkChain() pindexTest = pindexTest->pprev; } if (!fInvalidAncestor) + { return pindexNew; + } } while(true); } @@ -748,10 +819,10 @@ void InvalidChainFound(CBlockIndex* pindexNew) pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexNew->GetBlockTime())); - CBlockIndex *tip = chainActive.Tip(); + CBlockIndex *tip = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); assert (tip); LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__, - tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0), + tip->GetBlockHash().ToString(), pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime())); CheckForkWarningConditions(); } @@ -762,7 +833,8 @@ void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) if (state.IsInvalid(nDoS)) { std::map::iterator it = mapBlockSource.find(pindex->GetBlockHash()); - if (it != mapBlockSource.end() && State(it->second)) { + if (it != mapBlockSource.end() && State(it->second)) + { assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()}; State(it->second)->rejects.push_back(reject); @@ -777,3 +849,561 @@ void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) InvalidChainFound(pindex); } } + + +bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize) +{ + pos.nFile = nFile; + + LOCK(cs_LastBlockFile); + + unsigned int nNewSize; + pos.nPos = vinfoBlockFile[nFile].nUndoSize; + nNewSize = vinfoBlockFile[nFile].nUndoSize += nAddSize; + setDirtyFileInfo.insert(nFile); + + unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; + unsigned int nNewChunks = (nNewSize + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; + if (nNewChunks > nOldChunks) { + if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) { + FILE *file = OpenUndoFile(pos); + if (file) { + LogPrintf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); + AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); + fclose(file); + } + } + else + return state.Error("out of disk space"); + } + + return true; +} + +bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart) +{ + // Open history file to append + CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); + if (fileout.IsNull()) + return error("%s: OpenUndoFile failed", __func__); + + // Write index header + unsigned int nSize = GetSerializeSize(fileout,blockundo); + fileout << FLATDATA(messageStart) << nSize; + + // Write undo data + long fileOutPos = ftell(fileout.Get()); + if (fileOutPos < 0) + return error("%s: ftell failed", __func__); + pos.nPos = (unsigned int)fileOutPos; + fileout << blockundo; + + // calculate & write checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << blockundo; + fileout << hasher.GetHash(); + + return true; +} + +bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock) +{ + // Open history file to read + CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) + return error("%s: OpenBlockFile failed", __func__); + + // Read block + uint256 hashChecksum; + try { + filein >> blockundo; + filein >> hashChecksum; + } + catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + + // Verify checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << blockundo; + if (hashChecksum != hasher.GetHash()) + return error("%s: Checksum mismatch", __func__); + + return true; +} + +static CCheckQueue scriptcheckqueue(128); + +void ThreadScriptCheck() { + RenameThread("bitcoin-scriptch"); + scriptcheckqueue.Thread(); +} +static int64_t nTimeCheck = 0; +static int64_t nTimeForks = 0; +static int64_t nTimeVerify = 0; +static int64_t nTimeConnect = 0; +static int64_t nTimeIndex = 0; +static int64_t nTimeCallbacks = 0; + +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) +{ + const CNetworkTemplate& chainparams = pnetMan->getActivePaymentNetwork(); + AssertLockHeld(cs_main); + + int64_t nTimeStart = GetTimeMicros(); + + if(pindex->GetBlockHash() != chainparams.GetConsensus().hashGenesisBlock) + { + /// once updateForPos runs the only flags that should be enabled are the ones that determine if PoS block or not + /// before this runs there should have been no flags set. so it is ok to reset the flags to 0 + pindex->updateForPos(block); + } + + // Check it again in case a previous version let a bad block in + if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) + return false; + + // verify that the view's current state corresponds to the previous block + uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); + assert(hashPrevBlock == view.GetBestBlock()); + + // Special case for the genesis block, skipping connection of its transactions + // (its coinbase is unspendable) + if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { + if (!fJustCheck) + view.SetBestBlock(pindex->GetBlockHash()); + return true; + } + + bool fScriptChecks = true; + if (fCheckpointsEnabled) { + CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints()); + if (pindexLastCheckpoint && pindexLastCheckpoint->GetAncestor(pindex->nHeight) == pindex) { + // This block is an ancestor of a checkpoint: disable script checks + fScriptChecks = false; + } + } + + + int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart; + LogPrint("bench", " - Sanity checks: %.2fms [%.2fs]\n", 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001); + { + for(auto const& tx: block.vtx) + { + const CCoins* coins = view.AccessCoins(tx.GetHash()); + if (coins && !coins->IsPruned()) + return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"), + REJECT_INVALID, "bad-txns-BIP30"); + } + } + + unsigned int flags = SCRIPT_VERIFY_P2SH; + + // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, + // when 75% of the network has upgraded: + if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { + flags |= SCRIPT_VERIFY_DERSIG; + } + + // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4 + // blocks, when 75% of the network has upgraded: + if (block.nVersion >= 4 && IsSuperMajority(4, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { + flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; + } + + // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic. + int nLockTimeFlags = 0; + flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; + nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; + + int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1; + LogPrint("bench", " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001); + + CBlockUndo blockundo; + + CCheckQueueControl control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); + + std::vector prevheights; + CAmount nFees = 0; + CAmount nValueIn = 0; + CAmount nValueOut = 0; + int nInputs = 0; + unsigned int nSigOps = 0; + CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); + std::vector > vPos; + vPos.reserve(block.vtx.size()); + blockundo.vtxundo.reserve(block.vtx.size() - 1); + for (unsigned int i = 0; i < block.vtx.size(); i++) + { + const CTransaction &tx = block.vtx[i]; + + nInputs += tx.vin.size(); + nSigOps += GetLegacySigOpCount(tx); + if (nSigOps > MAX_BLOCK_SIGOPS) + return state.DoS(100, error("ConnectBlock(): too many sigops"), + REJECT_INVALID, "bad-blk-sigops"); + + if (tx.IsCoinBase()) + { + nValueOut += tx.GetValueOut(); + } + if (!tx.IsCoinBase()) + { + if (!view.HaveInputs(tx)) + { + return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), + REJECT_INVALID, "bad-txns-inputs-missingorspent"); + } + + // Check that transaction is BIP68 final + // BIP68 lock checks (as opposed to nLockTime checks) must + // be in ConnectBlock because they require the UTXO set + prevheights.resize(tx.vin.size()); + for (size_t j = 0; j < tx.vin.size(); j++) { + prevheights[j] = view.AccessCoins(tx.vin[j].prevout.hash)->nHeight; + } + + if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) { + return state.DoS(100, error("%s: contains a non-BIP68-final transaction", __func__), + REJECT_INVALID, "bad-txns-nonfinal"); + } + + { + // Add in sigops done by pay-to-script-hash inputs; + // this is to prevent a "rogue miner" from creating + // an incredibly-expensive-to-validate block. + nSigOps += GetP2SHSigOpCount(tx, view); + if (nSigOps > MAX_BLOCK_SIGOPS) + return state.DoS(100, error("ConnectBlock(): too many sigops"), + REJECT_INVALID, "bad-blk-sigops"); + } + + CAmount nTxValueIn = view.GetValueIn(tx); + CAmount nTxValueOut = tx.GetValueOut(); + + if (!tx.IsCoinStake()) + { + nFees += nTxValueIn - nTxValueOut; + } + + nValueIn += nTxValueIn; + nValueOut += nTxValueOut; + + std::vector vChecks; + bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ + if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL)) + return error("ConnectBlock(): CheckInputs on %s failed with %s", + tx.GetHash().ToString(), FormatStateMessage(state)); + control.Add(vChecks); + } + + CTxUndo undoDummy; + if (i > 0) { + blockundo.vtxundo.push_back(CTxUndo()); + } + UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); + + vPos.push_back(std::make_pair(tx.GetHash(), pos)); + pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); + } + + + int64_t nTime3 = GetTimeMicros(); + nTimeConnect += nTime3 - nTime2; + LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001); + CAmount blockReward = 0; + + /// after 1504000 no Pow blocks are allowed + if(block.IsProofOfWork() && pindex->nHeight >= 1504000) + { + return state.DoS(100, error("CheckBlock(): proof of work failed, invalid PoW height "), + REJECT_INVALID, "Pow after cutoff"); + } + + /// height >= 1504000 for legacy compatibility + /// someone made some blocks at 1493605 to roughly 1495000 that which didnt conform to the ideal blocks, but at the time the client allowed it + /// that person didnt break any rules and no funds were stolen from other people. + /// but we need to have this check now to prevent future blocks from doing the same thing. + + if(block.IsProofOfWork() && pindex->nHeight >= 1504000) + { + blockReward = GetProofOfWorkReward(nFees, pindex->nHeight, block.hashPrevBlock); + if (block.vtx[0].GetValueOut() > blockReward) + { + return state.DoS(100, + error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", + block.vtx[0].GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); + } + } + else + { + for(auto tx : block.vtx) + { + if(tx.IsCoinStake()) + { + uint64_t nCoinAge; + if (!tx.GetCoinAge(nCoinAge)) + return state.DoS(100, error("ConnectBlock() : %s unable to get coin age for coinstake", tx.GetHash().ToString().substr(0,10).c_str())); + blockReward = blockReward + GetProofOfStakeReward(tx.GetCoinAge(nCoinAge, true), pindex->nHeight); + } + } + if (block.vtx[0].GetValueOut() > blockReward && pindex->nHeight >= 1504000) + { + return state.DoS(100, + error("ConnectBlock(): coinstake pays too much"), REJECT_INVALID, "bad-cb-amount"); + } + } + retry: + if (!control.Wait()) + { + MilliSleep(50); + goto retry; + //return state.DoS(100, false); + } + int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; + LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * 0.000001); + + + // ppcoin: track money supply and mint amount info + pindex->nMint = nValueOut - nValueIn + nFees; + pindex->nMoneySupply = (pindex->pprev? pindex->pprev->nMoneySupply : 0) + nValueOut - nValueIn; + + + /// put the following checks in this function due to lack of pindex when checkblock is called + // Verify hash target and signature of coinstake tx + uint256 hashProofOfStake; + hashProofOfStake.SetNull(); + if (block.IsProofOfStake()) + { + if (!CheckProofOfStake(pindex->nHeight, block.vtx[1], hashProofOfStake)) + { + return state.DoS(100, error("WARNING: ProcessBlock(): check proof-of-stake failed for block %s\n", block.GetHash().ToString().c_str()), REJECT_INVALID, "bad-proofofstake"); + } + } + + // ppcoin: compute stake entropy bit for stake modifier + if (!pindex->SetStakeEntropyBit(block.GetStakeEntropyBit())) + { + return error("ConnectBlock() : SetStakeEntropyBit() failed"); + } + // ppcoin: record proof-of-stake hash value + pindex->hashProofOfStake = hashProofOfStake; + + // ppcoin: compute stake modifier + uint256 nStakeModifier; + nStakeModifier.SetNull(); + if(block.IsProofOfStake()) + { + if (!ComputeNextStakeModifier(pindex->pprev, block.vtx[1], nStakeModifier)) + return state.DoS(100, error("ConnectBlock() : ComputeNextStakeModifier() failed") , REJECT_INVALID, "bad-stakemodifier-pos"); + } + else + { + if (!ComputeNextStakeModifier(pindex->pprev, block.vtx[0], nStakeModifier)) + return state.DoS(100, error("ConnectBlock() : ComputeNextStakeModifier() failed"), REJECT_INVALID, "bad-stakemodifier-pow"); + } + pindex->SetStakeModifier(nStakeModifier); + if (fJustCheck) + return true; + + // Write undo information to disk + if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) + { + if (pindex->GetUndoPos().IsNull()) { + CDiskBlockPos pos; + if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40)) + return error("ConnectBlock(): FindUndoPos failed"); + if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) + return AbortNode(state, "Failed to write undo data"); + + // update nUndoPos in block index + pindex->nUndoPos = pos.nPos; + pindex->nStatus |= BLOCK_HAVE_UNDO; + } + pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); + setDirtyBlockIndex.insert(pindex); + } + + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree->WriteTxIndex(vPos)) + { + return AbortNode(state, "Failed to write transaction index"); + } + + // add this block to the view's block chain + view.SetBestBlock(pindex->GetBlockHash()); + + int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4; + LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001); + + // Watch for changes to the previous coinbase transaction. + static uint256 hashPrevBestCoinBase; + GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); + hashPrevBestCoinBase = block.vtx[0].GetHash(); + + int64_t nTime6 = GetTimeMicros(); nTimeCallbacks += nTime6 - nTime5; + LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001); + + return true; +} + +/** + * Apply the undo operation of a CTxInUndo to the given chain state. + * @param undo The undo object. + * @param view The coins view to which to apply the changes. + * @param out The out point that corresponds to the tx input. + * @return True on success. + */ +bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out) +{ + bool fClean = true; + + CCoinsModifier coins = view.ModifyCoins(out.hash); + if (undo.nHeight != 0) { + // undo data contains height: this is the last output of the prevout tx being spent + if (!coins->IsPruned()) + fClean = fClean && error("%s: undo data overwriting existing transaction", __func__); + coins->Clear(); + coins->fCoinBase = undo.fCoinBase; + coins->nHeight = undo.nHeight; + coins->nVersion = undo.nVersion; + } else { + if (coins->IsPruned()) + fClean = fClean && error("%s: undo data adding output to missing transaction", __func__); + } + if (coins->IsAvailable(out.n)) + fClean = fClean && error("%s: undo data overwriting existing output", __func__); + if (coins->vout.size() < out.n+1) + coins->vout.resize(out.n+1); + coins->vout[out.n] = undo.txout; + + return fClean; +} + + +bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean) +{ + assert(pindex->GetBlockHash() == view.GetBestBlock()); + + if (pfClean) + *pfClean = false; + + bool fClean = true; + + CBlockUndo blockUndo; + CDiskBlockPos pos = pindex->GetUndoPos(); + if (pos.IsNull()) + return error("DisconnectBlock(): no undo data available"); + if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) + return error("DisconnectBlock(): failure reading undo data"); + + if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) + return error("DisconnectBlock(): block and undo data inconsistent"); + + // undo transactions in reverse order + for (int i = block.vtx.size() - 1; i >= 0; i--) { + const CTransaction &tx = block.vtx[i]; + uint256 hash = tx.GetHash(); + + // Check that all outputs are available and match the outputs in the block itself + // exactly. + { + CCoinsModifier outs = view.ModifyCoins(hash); + outs->ClearUnspendable(); + + CCoins outsBlock(tx, pindex->nHeight); + // The CCoins serialization does not serialize negative numbers. + // No network rules currently depend on the version here, so an inconsistency is harmless + // but it must be corrected before txout nversion ever influences a network rule. + if (outsBlock.nVersion < 0) + outs->nVersion = outsBlock.nVersion; + if (*outs != outsBlock) + fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted"); + + // remove outputs + outs->Clear(); + } + + // restore inputs + if (i > 0) { // not coinbases + const CTxUndo &txundo = blockUndo.vtxundo[i-1]; + if (txundo.vprevout.size() != tx.vin.size()) + return error("DisconnectBlock(): transaction and undo data inconsistent"); + for (unsigned int j = tx.vin.size(); j-- > 0;) { + const COutPoint &out = tx.vin[j].prevout; + const CTxInUndo &undo = txundo.vprevout[j]; + if (!ApplyTxInUndo(undo, view, out)) + fClean = false; + } + } + } + + // move best block pointer to prevout block + view.SetBestBlock(pindex->pprev->GetBlockHash()); + + if (pfClean) { + *pfClean = fClean; + return true; + } + + return fClean; +} + +/** Comparison function for sorting the getchaintips heads. */ +struct CompareBlocksByHeight +{ + bool operator()(const CBlockIndex* a, const CBlockIndex* b) const + { + /* Make sure that unequal blocks with the same height do not compare + equal. Use the pointers themselves to make a distinction. */ + + if (a->nHeight != b->nHeight) + return (a->nHeight > b->nHeight); + + return a < b; + } +}; + +void removeImpossibleChainTips() +{ + int deletionCount = 0; + std::set setTips; + for (auto& item: pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex) + setTips.insert(item.second); + for (auto& item: pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex) + { + CBlockIndex* pprev = item.second->pprev; + if (pprev) + setTips.erase(pprev); + } + + setTips.insert(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()); + + const int currentHeight = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height(); + for (CBlockIndex* block : setTips) + { + const int tipHeight = block->nHeight; + const int forkHeight = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.FindFork(block)->nHeight; + const int branchLen = tipHeight - forkHeight; + std::string status = ""; + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(block)) + { + // This block is part of the currently active chain. + status = "active"; + } + if(status != "active" && forkHeight < currentHeight - 50) + { + CBlockIndex* curBlock = block; + while(curBlock->nHeight > forkHeight) + { + pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree->EraseBlockIndex(curBlock->GetBlockHash()); + LogPrintf("cleaning up index %s \n", curBlock->GetBlockHash().ToString().c_str()); + deletionCount++; + curBlock = curBlock->pprev; + } + } + } + LogPrintf("found %i impossible indexes and deleted them \n", deletionCount); +} + diff --git a/src/processblock.h b/src/processblock.h index 8491fe0a..d456c84a 100644 --- a/src/processblock.h +++ b/src/processblock.h @@ -8,7 +8,7 @@ class CValidationState; class CNode; class CBlock; -class CChainParams; +class CNetworkTemplate; class CDiskBlockPos; class CBlockIndex; @@ -17,9 +17,20 @@ extern bool fLargeWorkInvalidChainFound; CBlockIndex* FindMostWorkChain(); void CheckBlockIndex(const Consensus::Params& consensusParams); -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp, BlockOrigin origin); +bool ProcessNewBlock(CValidationState& state, const CNetworkTemplate& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp, BlockOrigin origin); bool DisconnectTip(CValidationState& state, const Consensus::Params& consensusParams); void InvalidChainFound(CBlockIndex* pindexNew); void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state); +bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock); +/** Run an instance of the script checking thread */ +void ThreadScriptCheck(); +/** Apply the effects of this block (with given index) on the UTXO set represented by coins */ +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); +/** Undo the effects of this block (with given index) on the UTXO set represented by coins. + * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean + * will be true if no problems were found. Otherwise, the return value will be false in case + * of problems. Note that in any case, coins may be modified. */ +bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL); +void removeImpossibleChainTips(); #endif // PROCESSBLOCK_H diff --git a/src/processheader.cpp b/src/processheader.cpp index 8e9c801d..efa82f7a 100644 --- a/src/processheader.cpp +++ b/src/processheader.cpp @@ -1,20 +1,21 @@ #include "processheader.h" #include "main.h" -#include "util.h" +#include "util/util.h" #include "timedata.h" +#include "init.h" -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) +bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CNetworkTemplate& chainparams, CBlockIndex** ppindex) { AssertLockHeld(cs_main); // Check for duplicate uint256 hash = block.GetHash(); - BlockMap::iterator miSelf = mapBlockIndex.find(hash); + BlockMap::iterator miSelf = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(hash); CBlockIndex *pindex = NULL; if (hash != chainparams.GetConsensus().hashGenesisBlock) { - if (miSelf != mapBlockIndex.end()) { + if (miSelf != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) { // Block header is already known. pindex = miSelf->second; if (ppindex) @@ -29,8 +30,8 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const // Get prev block index CBlockIndex* pindexPrev = NULL; - BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); - if (mi == mapBlockIndex.end()) + BlockMap::iterator mi = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(block.hashPrevBlock); + if (mi == pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk"); pindexPrev = (*mi).second; if (pindexPrev->nStatus & BLOCK_FAILED_MASK) @@ -44,7 +45,7 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const return false; } if (pindex == NULL) - pindex = AddToBlockIndex(block); + pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->AddToBlockIndex(block); if (ppindex) *ppindex = pindex; diff --git a/src/processheader.h b/src/processheader.h index 7b8d5fa4..488e02ca 100644 --- a/src/processheader.h +++ b/src/processheader.h @@ -1,12 +1,11 @@ #ifndef PROCESSHEADER_H #define PROCESSHEADER_H -#include "primitives/block.h" #include "validationinterface.h" -#include "chainparams.h" +#include "networks/networktemplate.h" bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev); -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex=NULL); +bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CNetworkTemplate& chainparams, CBlockIndex** ppindex=NULL); #endif // PROCESSHEADER_H diff --git a/src/processtx.cpp b/src/processtx.cpp new file mode 100644 index 00000000..a90f9130 --- /dev/null +++ b/src/processtx.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2017 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "tx/tx.h" +#include "tx/servicetx.h" +#include "validationinterface.h" +#include "main.h" +#include "consensus/consensus.h" + +bool CheckTransaction(const CTransaction& tx, CValidationState &state) +{ + // Basic checks that don't depend on any context + if (tx.vin.empty()) + return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty"); + if (tx.vout.empty()) + return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty"); + // Size limits + if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize"); + + // Check for negative or overflow output values + CAmount nValueOut = 0; + for (auto const& txout: tx.vout) + { + if (txout.nValue < 0) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative"); + if (txout.nValue > MAX_MONEY) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge"); + nValueOut += txout.nValue; + if (!MoneyRange(nValueOut)) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge"); + } + + // Check for duplicate inputs + std::set vInOutPoints; + for (auto const& txin: tx.vin) + { + if (vInOutPoints.count(txin.prevout)) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate"); + vInOutPoints.insert(txin.prevout); + } + + if (tx.IsCoinBase()) + { + if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100) + return state.DoS(100, false, REJECT_INVALID, "bad-cb-length"); + } + else + { + for (auto const& txin: tx.vin) + if (txin.prevout.IsNull()) + return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null"); + } + + return true; +} diff --git a/src/processtx.h b/src/processtx.h new file mode 100644 index 00000000..200554b7 --- /dev/null +++ b/src/processtx.h @@ -0,0 +1,11 @@ +// Copyright (c) 2017 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef TXVALIDATION_H +#define TXVALIDATION_H + +/** Context-independent validity checks */ +bool CheckTransaction(const CTransaction& tx, CValidationState& state); + +#endif // TXVALIDATION_H diff --git a/src/protocol.cpp b/src/protocol.cpp index c1c7c0b9..15c68cb2 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -5,8 +5,8 @@ #include "protocol.h" -#include "util.h" -#include "utilstrencodings.h" +#include "util/util.h" +#include "util/utilstrencodings.h" #ifndef WIN32 # include diff --git a/src/protocol.h b/src/protocol.h index af2d571e..8f48c69e 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -40,7 +40,7 @@ class CMessageHeader ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(FLATDATA(pchMessageStart)); READWRITE(FLATDATA(pchCommand)); @@ -225,7 +225,7 @@ extern const char *SENDHEADERS; const std::vector &getAllNetMessageTypes(); /** nServices flags */ -enum { +enum ServiceFlags : uint64_t { // NODE_NETWORK means that the node is capable of serving the block chain. It is currently // set by all Bitcoin Core nodes, and is unset by SPV clients or other peers that just want // network services but don't provide them. @@ -260,19 +260,20 @@ class CAddress : public CService ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) - { + inline void SerializationOp(Stream& s, Operation ser_action) { if (ser_action.ForRead()) Init(); - if (nType & SER_DISK) + int nVersion = s.GetVersion(); + if (s.GetType() & SER_DISK) READWRITE(nVersion); - if ((nType & SER_DISK) || !(nType & SER_GETHASH)) + if ((s.GetType() & SER_DISK) || !(s.GetType() & SER_GETHASH)) READWRITE(nTime); - READWRITE(nServices); + uint64_t nServicesInt = nServices; + READWRITE(nServicesInt); + nServices = (ServiceFlags)nServicesInt; READWRITE(*(CService*)this); } - } // TODO: make private (improves encapsulation) public: @@ -293,7 +294,7 @@ class CInv ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(type); READWRITE(hash); diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 2e428a47..5d0aa5bd 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -10,11 +10,6 @@ #include "crypto/hmac_sha512.h" #include "random.h" -#include -#include -#include -#include - #include #include @@ -178,7 +173,9 @@ static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1 bool CPubKey::Verify(const uint256 &hash, const std::vector& vchSig) const { if (!IsValid()) + { return false; + } CECKey key; if (!key.SetPubKey(*this)) { diff --git a/src/pubkey.h b/src/pubkey.h index 2bdd7b36..39c53f68 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -6,7 +6,7 @@ #ifndef BITCOIN_PUBKEY_H #define BITCOIN_PUBKEY_H -#include "hash.h" +#include "crypto/hash.h" #include "serialize.h" #include "uint256.h" @@ -119,14 +119,14 @@ class CPubKey return size() + 1; } template - void Serialize(Stream& s, int nType, int nVersion) const + void Serialize(Stream& s) const { unsigned int len = size(); ::WriteCompactSize(s, len); s.write((char*)vch, len); } template - void Unserialize(Stream& s, int nType, int nVersion) + void Unserialize(Stream& s) { unsigned int len = ::ReadCompactSize(s); if (len <= 65) { diff --git a/src/random.cpp b/src/random.cpp index 6155c0d8..506812b3 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -5,23 +5,63 @@ #include "random.h" +#include "crypto/sha512.h" #include "support/cleanse.h" #ifdef WIN32 #include "compat.h" // for Windows API +#include #endif -#include "serialize.h" // for begin_ptr(vec) -#include "util.h" // for LogPrint() -#include "utilstrencodings.h" // for GetTime() - +#include "util/util.h" // for LogPrint() +#include "util/utilstrencodings.h" // for GetTime() +#include "serialize.h" +#include #include #ifndef WIN32 #include #endif +#ifdef HAVE_SYS_GETRANDOM +#include +#include +#endif +#ifdef HAVE_GETENTROPY +#include +#endif +#ifdef HAVE_SYSCTL_ARND +#include +#endif + #include #include +static void RandFailure() { + LogPrintf("Failed to read randomness, aborting\n"); + abort(); +} + +#ifndef WIN32 +/** + *Fallback: get 32 bytes of system entropy from /dev/urandom. The most + *compatible way to get cryptographic randomness on UNIX-ish platforms. + */ +void GetDevURandom(unsigned char *ent32) { + int f = open("/dev/urandom", O_RDONLY); + if (f == -1) { + RandFailure(); + } + int have = 0; + do { + ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have); + if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) { + RandFailure(); + } + have += n; + } while (have < NUM_OS_RANDOM_BYTES); + close(f); +} +#endif + static inline int64_t GetPerformanceCounter() { int64_t nCounter = 0; @@ -43,6 +83,68 @@ void RandAddSeed() memory_cleanse((void*)&nCounter, sizeof(nCounter)); } +/** Get 32 bytes of system entropy. */ +void GetOSRand(uint8_t *ent32) { +#if defined(WIN32) + HCRYPTPROV hProvider; + int ret = CryptAcquireContextW(&hProvider, nullptr, nullptr, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT); + if (!ret) { + RandFailure(); + } + ret = CryptGenRandom(hProvider, NUM_OS_RANDOM_BYTES, ent32); + if (!ret) { + RandFailure(); + } + CryptReleaseContext(hProvider, 0); +#elif defined(HAVE_SYS_GETRANDOM) + /** + * Linux. From the getrandom(2) man page: + * "If the urandom source has been initialized, reads of up to 256 bytes + * will always return as many bytes as requested and will not be interrupted + * by signals." + */ + int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0); + if (rv != NUM_OS_RANDOM_BYTES) { + if (rv < 0 && errno == ENOSYS) { + /* Fallback for kernel <3.17: the return value will be -1 and errno + * ENOSYS if the syscall is not available, in that case fall back + * to /dev/urandom. + */ + GetDevURandom(ent32); + } else { + RandFailure(); + } + } +#elif defined(HAVE_GETENTROPY) + /* On OpenBSD this can return up to 256 bytes of entropy, will return an + * error if more are requested. + * The call cannot return less than the requested number of bytes. + */ + if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) { + RandFailure(); + } +#elif defined(HAVE_SYSCTL_ARND) + /* FreeBSD and similar. It is possible for the call to return less + * bytes than requested, so need to read in a loop. + */ + static const int name[2] = {CTL_KERN, KERN_ARND}; + int have = 0; + do { + size_t len = NUM_OS_RANDOM_BYTES - have; + if (sysctl(name, ARRAYLEN(name), ent32 + have, &len, nullptr, 0) != 0) { + RandFailure(); + } + have += len; + } while (have < NUM_OS_RANDOM_BYTES); +#else + /* Fall back to /dev/urandom if there is no specific method implemented to + * get system entropy for this OS. + */ + GetDevURandom(ent32); +#endif +} + void RandAddSeedPerfmon() { RandAddSeed(); @@ -137,3 +239,57 @@ void seed_insecure_rand(bool fDeterministic) insecure_rand_Rw = tmp; } } + + +void FastRandomContext::RandomSeed() { + uint256 seed = GetRandHash(); + rng.SetKey(seed.begin(), 32); + requires_seed = false; +} + +FastRandomContext::FastRandomContext(const uint256 &seed) + : requires_seed(false), bytebuf_size(0), bitbuf_size(0) { + rng.SetKey(seed.begin(), 32); +} + +bool Random_SanityCheck() { + /* This does not measure the quality of randomness, but it does test that + * OSRandom() overwrites all 32 bytes of the output given a maximum number + * of tries. + */ + static const ssize_t MAX_TRIES = 1024; + uint8_t data[NUM_OS_RANDOM_BYTES]; + /* Tracks which bytes have been overwritten at least once */ + bool overwritten[NUM_OS_RANDOM_BYTES] = {}; + int num_overwritten; + int tries = 0; + /* Loop until all bytes have been overwritten at least once, or max number + * tries reached */ + do { + memset(data, 0, NUM_OS_RANDOM_BYTES); + GetOSRand(data); + for (int x = 0; x < NUM_OS_RANDOM_BYTES; ++x) { + overwritten[x] |= (data[x] != 0); + } + + num_overwritten = 0; + for (int x = 0; x < NUM_OS_RANDOM_BYTES; ++x) { + if (overwritten[x]) { + num_overwritten += 1; + } + } + + tries += 1; + } while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES); + /* If this failed, bailed out after too many tries */ + return (num_overwritten == NUM_OS_RANDOM_BYTES); +} + +FastRandomContext::FastRandomContext(bool fDeterministic) + : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0) { + if (!fDeterministic) { + return; + } + uint256 seed; + rng.SetKey(seed.begin(), 32); +} diff --git a/src/random.h b/src/random.h index 1a2d3e8e..ffbc075c 100644 --- a/src/random.h +++ b/src/random.h @@ -8,8 +8,29 @@ #include "uint256.h" +#include "crypto/chacha20.h" #include +uint64_t static inline CountBits(uint64_t x) { +#ifdef HAVE_DECL___BUILTIN_CLZL + if (sizeof(unsigned long) >= sizeof(uint64_t)) { + return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0; + } +#endif +#ifdef HAVE_DECL___BUILTIN_CLZLL + if (sizeof(unsigned long long) >= sizeof(uint64_t)) { + return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0; + } +#endif + int ret = 0; + while (x) { + x >>= 1; + ++ret; + } + return ret; +} + + /** * Seed OpenSSL PRNG with additional entropy data */ @@ -46,4 +67,108 @@ static inline uint32_t insecure_rand(void) return (insecure_rand_Rw << 16) + insecure_rand_Rz; } +/** + * Fast randomness source. This is seeded once with secure random data, but is + * completely deterministic and insecure after that. + * This class is not thread-safe. + */ +class FastRandomContext { +private: + bool requires_seed; + ChaCha20 rng; + + uint8_t bytebuf[64]; + int bytebuf_size; + + uint64_t bitbuf; + int bitbuf_size; + + void RandomSeed(); + + void FillByteBuffer() { + if (requires_seed) { + RandomSeed(); + } + rng.Output(bytebuf, sizeof(bytebuf)); + bytebuf_size = sizeof(bytebuf); + } + + void FillBitBuffer() { + bitbuf = rand64(); + bitbuf_size = 64; + } + +public: + explicit FastRandomContext(bool fDeterministic = false); + + /** Initialize with explicit seed (only for testing) */ + explicit FastRandomContext(const uint256 &seed); + + /** Generate a random 64-bit integer. */ + uint64_t rand64() { + if (bytebuf_size < 8) { + FillByteBuffer(); + } + uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size); + bytebuf_size -= 8; + return ret; + } + + /** Generate a random (bits)-bit integer. */ + uint64_t randbits(int bits) { + if (bits == 0) { + return 0; + } else if (bits > 32) { + return rand64() >> (64 - bits); + } else { + if (bitbuf_size < bits) { + FillBitBuffer(); + } + uint64_t ret = bitbuf & (~uint64_t(0) >> (64 - bits)); + bitbuf >>= bits; + bitbuf_size -= bits; + return ret; + } + } + + /** Generate a random integer in the range [0..range). */ + uint64_t randrange(uint64_t range) { + --range; + int bits = CountBits(range); + while (true) { + uint64_t ret = randbits(bits); + if (ret <= range) { + return ret; + } + } + } + + /** Generate a random 32-bit integer. */ + uint32_t rand32() { return randbits(32); } + + /** Generate a random boolean. */ + bool randbool() { return randbits(1); } +}; + +/** + * Number of random bytes returned by GetOSRand. + * When changing this constant make sure to change all call sites, and make sure + * that the underlying OS APIs for all platforms support the number (many cap + * out at 256 bytes). + */ +static const ssize_t NUM_OS_RANDOM_BYTES = 32; + +/** + * Get 32 bytes of system entropy. Do not use this in application code: use + * GetStrongRandBytes instead. + */ +void GetOSRand(unsigned char *ent32); + +/** + * Check that OS randomness is available and returning the requested number of + * bytes. + */ +bool Random_SanityCheck(); + + #endif // BITCOIN_RANDOM_H diff --git a/src/rest.cpp b/src/rest.cpp index 69b9e50a..2a3037d8 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -3,18 +3,18 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "chain.h" -#include "chainparams.h" -#include "primitives/block.h" -#include "primitives/transaction.h" +#include "chain/chain.h" +#include "networks/netman.h" +#include "tx/tx.h" #include "main.h" #include "httpserver.h" -#include "rpcserver.h" +#include "rpc/rpcserver.h" #include "streams.h" #include "sync.h" #include "txmempool.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include "version.h" +#include "init.h" #include #include @@ -48,7 +48,7 @@ struct CCoin { ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nTxVer); READWRITE(nHeight); @@ -150,13 +150,13 @@ static bool rest_headers(HTTPRequest* req, headers.reserve(count); { LOCK(cs_main); - BlockMap::const_iterator it = mapBlockIndex.find(hash); - const CBlockIndex *pindex = (it != mapBlockIndex.end()) ? it->second : NULL; - while (pindex != NULL && chainActive.Contains(pindex)) { + BlockMap::const_iterator it = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(hash); + const CBlockIndex *pindex = (it != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) ? it->second : NULL; + while (pindex != NULL && pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(pindex)) { headers.push_back(pindex); if (headers.size() == (unsigned long)count) break; - pindex = chainActive.Next(pindex); + pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Next(pindex); } } @@ -215,12 +215,12 @@ static bool rest_block(HTTPRequest* req, CBlockIndex* pblockindex = NULL; { LOCK(cs_main); - if (mapBlockIndex.count(hash) == 0) + if (pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(hash) == 0) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); - pblockindex = mapBlockIndex[hash]; + pblockindex = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[hash]; - if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) + if (!ReadBlockFromDisk(block, pblockindex, pnetMan->getActivePaymentNetwork()->GetConsensus())) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } @@ -357,7 +357,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) CTransaction tx; uint256 hashBlock = uint256(); - if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) + if (!GetTransaction(hash, tx, pnetMan->getActivePaymentNetwork()->GetConsensus(), hashBlock, true)) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); @@ -501,7 +501,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) CCoinsView viewDummy; CCoinsViewCache view(&viewDummy); - CCoinsViewCache& viewChain = *pcoinsTip; + CCoinsViewCache& viewChain = *pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip; CCoinsViewMemPool viewMempool(&viewChain, mempool); if (fCheckMemPool) @@ -535,7 +535,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) // serialize data // use exact same output as mentioned in Bip64 CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); - ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; + ssGetUTXOResponse << pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() << pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash() << bitmap << outs; std::string ssGetUTXOResponseString = ssGetUTXOResponse.str(); req->WriteHeader("Content-Type", "application/octet-stream"); @@ -545,7 +545,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) case RF_HEX: { CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); - ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; + ssGetUTXOResponse << pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() << pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash() << bitmap << outs; std::string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); @@ -558,8 +558,8 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) // pack in some essentials // use more or less the same output as mentioned in Bip64 - objGetUTXOResponse.push_back(Pair("chainHeight", chainActive.Height())); - objGetUTXOResponse.push_back(Pair("chaintipHash", chainActive.Tip()->GetBlockHash().GetHex())); + objGetUTXOResponse.push_back(Pair("chainHeight", pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height())); + objGetUTXOResponse.push_back(Pair("chaintipHash", pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash().GetHex())); objGetUTXOResponse.push_back(Pair("bitmap", bitmapStringRepresentation)); UniValue utxos(UniValue::VARR); diff --git a/src/rpc/events.h b/src/rpc/events.h new file mode 100644 index 00000000..cc6d29ae --- /dev/null +++ b/src/rpc/events.h @@ -0,0 +1,56 @@ +// 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_SUPPORT_EVENTS_H +#define BITCOIN_SUPPORT_EVENTS_H + +#include +#include + +#include +#include + +#define MAKE_RAII(type) \ +/* deleter */\ +struct type##_deleter {\ + void operator()(struct type* ob) {\ + type##_free(ob);\ + }\ +};\ +/* unique ptr typedef */\ +typedef std::unique_ptr raii_##type + +MAKE_RAII(event_base); +MAKE_RAII(event); +MAKE_RAII(evhttp); +MAKE_RAII(evhttp_request); +MAKE_RAII(evhttp_connection); + +inline raii_event_base obtain_event_base() { + auto result = raii_event_base(event_base_new()); + if (!result.get()) + throw std::runtime_error("cannot create event_base"); + return result; +} + +inline raii_event obtain_event(struct event_base* base, evutil_socket_t s, short events, event_callback_fn cb, void* arg) { + return raii_event(event_new(base, s, events, cb, arg)); +} + +inline raii_evhttp obtain_evhttp(struct event_base* base) { + return raii_evhttp(evhttp_new(base)); +} + +inline raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg) { + return raii_evhttp_request(evhttp_request_new(cb, arg)); +} + +inline raii_evhttp_connection obtain_evhttp_connection_base(struct event_base* base, std::string host, uint16_t port) { + auto result = raii_evhttp_connection(evhttp_connection_base_new(base, nullptr, host.c_str(), port)); + if (!result.get()) + throw std::runtime_error("create connection failed"); + return result; +} + +#endif // BITCOIN_SUPPORT_EVENTS_H diff --git a/src/rpcblockchain.cpp b/src/rpc/rpcblockchain.cpp similarity index 87% rename from src/rpcblockchain.cpp rename to src/rpc/rpcblockchain.cpp index 7e265217..cf97635d 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpc/rpcblockchain.cpp @@ -4,21 +4,24 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "amount.h" -#include "chain.h" -#include "chainparams.h" -#include "checkpoints.h" +#include "chain/chain.h" +#include "networks/networktemplate.h" +#include "networks/netman.h" +#include "chain/checkpoints.h" #include "coins.h" #include "consensus/validation.h" #include "main.h" #include "policy/policy.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include "rpcserver.h" #include "streams.h" #include "sync.h" #include "txmempool.h" -#include "util.h" +#include "util/util.h" #include "args.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" +#include "init.h" +#include "verifydb.h" #include @@ -33,10 +36,10 @@ double GetDifficulty(const CBlockIndex* blockindex) // minimum difficulty = 1.0. if (blockindex == NULL) { - if (chainActive.Tip() == NULL) + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip() == NULL) return 1.0; else - blockindex = chainActive.Tip(); + blockindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); } int nShift = (blockindex->nBits >> 24) & 0xff; @@ -64,8 +67,8 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) 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)) - confirmations = chainActive.Height() - blockindex->nHeight + 1; + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(blockindex)) + confirmations = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - blockindex->nHeight + 1; result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", blockindex->nVersion)); @@ -79,7 +82,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); - CBlockIndex *pnext = chainActive.Next(blockindex); + CBlockIndex *pnext = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; @@ -91,8 +94,8 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain - if (chainActive.Contains(blockindex)) - confirmations = chainActive.Height() - blockindex->nHeight + 1; + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(blockindex)) + confirmations = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - blockindex->nHeight + 1; result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); @@ -121,7 +124,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); - CBlockIndex *pnext = chainActive.Next(blockindex); + CBlockIndex *pnext = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); result.push_back(Pair("flags", strprintf("%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work"))); @@ -149,7 +152,7 @@ UniValue getblockcount(const UniValue& params, bool fHelp) ); LOCK(cs_main); - return chainActive.Height(); + return pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height(); } UniValue getbestblockhash(const UniValue& params, bool fHelp) @@ -166,7 +169,7 @@ UniValue getbestblockhash(const UniValue& params, bool fHelp) ); LOCK(cs_main); - return chainActive.Tip()->GetBlockHash().GetHex(); + return pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash().GetHex(); } UniValue getdifficulty(const UniValue& params, bool fHelp) @@ -202,7 +205,7 @@ UniValue mempoolToJSON(bool fVerbose = false) info.push_back(Pair("time", e.GetTime())); info.push_back(Pair("height", (int)e.GetHeight())); info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight()))); - info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height()))); + info.push_back(Pair("currentpriority", e.GetPriority(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height()))); info.push_back(Pair("descendantcount", e.GetCountWithDescendants())); info.push_back(Pair("descendantsize", e.GetSizeWithDescendants())); info.push_back(Pair("descendantfees", e.GetModFeesWithDescendants())); @@ -301,10 +304,10 @@ UniValue getblockhash(const UniValue& params, bool fHelp) LOCK(cs_main); int nHeight = params[0].get_int(); - if (nHeight < 0 || nHeight > chainActive.Height()) + if (nHeight < 0 || nHeight > pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); - CBlockIndex* pblockindex = chainActive[nHeight]; + CBlockIndex* pblockindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive[nHeight]; return pblockindex->GetBlockHash().GetHex(); } @@ -350,10 +353,10 @@ UniValue getblockheader(const UniValue& params, bool fHelp) if (params.size() > 1) fVerbose = params[1].get_bool(); - if (mapBlockIndex.count(hash) == 0) + if (pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(hash) == 0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - CBlockIndex* pblockindex = mapBlockIndex[hash]; + CBlockIndex* pblockindex = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[hash]; if (!fVerbose) { @@ -413,13 +416,13 @@ UniValue getblock(const UniValue& params, bool fHelp) if (params.size() > 1) fVerbose = params[1].get_bool(); - if (mapBlockIndex.count(hash) == 0) + if (pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(hash) == 0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); CBlock block; - CBlockIndex* pblockindex = mapBlockIndex[hash]; + CBlockIndex* pblockindex = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[hash]; - if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) + if(!ReadBlockFromDisk(block, pblockindex, pnetMan->getActivePaymentNetwork()->GetConsensus())) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); if (!fVerbose) @@ -459,7 +462,7 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) CCoinsStats stats; FlushStateToDisk(); - if (pcoinsTip->GetStats(stats)) { + if (pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->GetStats(stats)) { ret.push_back(Pair("height", (int64_t)stats.nHeight)); ret.push_back(Pair("bestblock", stats.hashBlock.GetHex())); ret.push_back(Pair("transactions", (int64_t)stats.nTransactions)); @@ -523,18 +526,18 @@ UniValue gettxout(const UniValue& params, bool fHelp) CCoins coins; if (fMempool) { LOCK(mempool.cs); - CCoinsViewMemPool view(pcoinsTip, mempool); + CCoinsViewMemPool view(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get(), mempool); if (!view.GetCoins(hash, coins)) return NullUniValue; mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool } else { - if (!pcoinsTip->GetCoins(hash, coins)) + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->GetCoins(hash, coins)) return NullUniValue; } if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull()) return NullUniValue; - BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); + BlockMap::iterator it = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->GetBestBlock()); CBlockIndex *pindex = it->second; ret.push_back(Pair("bestblock", pindex->GetBlockHash().GetHex())); if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT) @@ -576,7 +579,7 @@ UniValue verifychain(const UniValue& params, bool fHelp) if (params.size() > 1) nCheckDepth = params[1].get_int(); - return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth); + return CVerifyDB().VerifyDB(pnetMan->getActivePaymentNetwork(), pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get(), nCheckLevel, nCheckDepth); } /** Implementation of IsSuperMajority with better feedback */ @@ -609,7 +612,7 @@ 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 BIP9SoftForkDesc(const std::string& name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) { UniValue rv(UniValue::VOBJ); rv.push_back(Pair("id", name)); @@ -669,23 +672,23 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) LOCK(cs_main); UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("chain", Params().NetworkIDString())); - obj.push_back(Pair("blocks", (int)chainActive.Height())); - obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); - obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex())); + obj.push_back(Pair("chain", pnetMan->getActivePaymentNetwork()->NetworkIDString())); + obj.push_back(Pair("blocks", (int)pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height())); + obj.push_back(Pair("headers", pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader ? pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader->nHeight : -1)); + obj.push_back(Pair("bestblockhash", pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash().GetHex())); obj.push_back(Pair("difficulty", (double)GetDifficulty())); - obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast())); - obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()))); - obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); + obj.push_back(Pair("mediantime", (int64_t)pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetMedianTimePast())); + obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(pnetMan->getActivePaymentNetwork()->Checkpoints(), pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()))); + obj.push_back(Pair("chainwork", pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nChainWork.GetHex())); - const Consensus::Params& consensusParams = Params().GetConsensus(); - CBlockIndex* tip = chainActive.Tip(); + const Consensus::Params& consensusParams = pnetMan->getActivePaymentNetwork()->GetConsensus(); + CBlockIndex* tip = pnetMan->getActivePaymentNetwork()->getChainManager()->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)); - bip9_softforks.push_back(BIP9SoftForkDesc("csv", consensusParams, Consensus::DEPLOYMENT_CSV)); + bip9_softforks.push_back(Pair("csv", "active")); obj.push_back(Pair("softforks", softforks)); obj.push_back(Pair("bip9_softforks", bip9_softforks)); return obj; @@ -745,9 +748,9 @@ UniValue getchaintips(const UniValue& params, bool fHelp) known blocks, and successively remove blocks that appear as pprev of another block. */ std::set setTips; - for (auto const& item: mapBlockIndex) + for (auto const& item: pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex) setTips.insert(item.second); - for (auto const& item: mapBlockIndex) + for (auto const& item: pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex) { const CBlockIndex* pprev = item.second->pprev; if (pprev) @@ -755,7 +758,7 @@ UniValue getchaintips(const UniValue& params, bool fHelp) } // Always report the currently active tip. - setTips.insert(chainActive.Tip()); + setTips.insert(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()); /* Construct the output array. */ UniValue res(UniValue::VARR); @@ -765,11 +768,11 @@ UniValue getchaintips(const UniValue& params, bool fHelp) obj.push_back(Pair("height", block->nHeight)); obj.push_back(Pair("hash", block->phashBlock->GetHex())); - const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight; + const int branchLen = block->nHeight - pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.FindFork(block)->nHeight; obj.push_back(Pair("branchlen", branchLen)); std::string status; - if (chainActive.Contains(block)) { + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(block)) { // This block is part of the currently active chain. status = "active"; } else if (block->nStatus & BLOCK_FAILED_MASK) { @@ -851,15 +854,15 @@ UniValue invalidateblock(const UniValue& params, bool fHelp) { LOCK(cs_main); - if (mapBlockIndex.count(hash) == 0) + if (pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(hash) == 0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - CBlockIndex* pblockindex = mapBlockIndex[hash]; - InvalidateBlock(state, Params().GetConsensus(), pblockindex); + CBlockIndex* pblockindex = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[hash]; + InvalidateBlock(state, pnetMan->getActivePaymentNetwork()->GetConsensus(), pblockindex); } if (state.IsValid()) { - ActivateBestChain(state, Params(), LOADED); + ActivateBestChain(state, pnetMan->getActivePaymentNetwork(), LOADED); } if (!state.IsValid()) { @@ -890,15 +893,15 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp) { LOCK(cs_main); - if (mapBlockIndex.count(hash) == 0) + if (pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(hash) == 0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - CBlockIndex* pblockindex = mapBlockIndex[hash]; + CBlockIndex* pblockindex = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[hash]; ReconsiderBlock(state, pblockindex); } if (state.IsValid()) { - ActivateBestChain(state, Params(), LOADED); + ActivateBestChain(state, pnetMan->getActivePaymentNetwork(), LOADED); } if (!state.IsValid()) { diff --git a/src/rpcclient.cpp b/src/rpc/rpcclient.cpp similarity index 77% rename from src/rpcclient.cpp rename to src/rpc/rpcclient.cpp index 56eca84c..797faaa7 100644 --- a/src/rpcclient.cpp +++ b/src/rpc/rpcclient.cpp @@ -6,7 +6,7 @@ #include "rpcclient.h" #include "rpcprotocol.h" -#include "util.h" +#include "util/util.h" #include #include @@ -19,6 +19,8 @@ class CRPCConvertParam public: std::string methodName; //! method whose params want conversion int paramIdx; //! 0-based idx of param to convert + std::string paramName; //!< parameter name + }; static const CRPCConvertParam vRPCConvertParams[] = @@ -26,8 +28,6 @@ static const CRPCConvertParam vRPCConvertParams[] = { "stop", 0 }, { "setmocktime", 0 }, { "getaddednodeinfo", 0 }, - { "setgenerate", 0 }, - { "setgenerate", 1 }, { "generate", 0 }, { "getnetworkhashps", 0 }, { "getnetworkhashps", 1 }, @@ -55,6 +55,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "listaccounts", 0 }, { "listaccounts", 1 }, { "walletpassphrase", 1 }, + { "walletpassphrase", 2 }, { "getblocktemplate", 0 }, { "listsinceblock", 1 }, { "listsinceblock", 2 }, @@ -106,6 +107,8 @@ class CRPCConvertTable { private: std::set > members; + std::set> membersByName; + public: CRPCConvertTable(); @@ -113,6 +116,9 @@ class CRPCConvertTable bool convert(const std::string& method, int idx) { return (members.count(std::make_pair(method, idx)) > 0); } + bool convert(const std::string& method, const std::string& name) { + return (membersByName.count(std::make_pair(method, name)) > 0); + } }; CRPCConvertTable::CRPCConvertTable() @@ -123,6 +129,8 @@ CRPCConvertTable::CRPCConvertTable() for (unsigned int i = 0; i < n_elem; i++) { members.insert(std::make_pair(vRPCConvertParams[i].methodName, vRPCConvertParams[i].paramIdx)); + membersByName.insert(std::make_pair(vRPCConvertParams[i].methodName, + vRPCConvertParams[i].paramName)); } } @@ -160,3 +168,27 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector &strParams) +{ + UniValue params(UniValue::VOBJ); + + for (const std::string &s: strParams) { + size_t pos = s.find("="); + if (pos == std::string::npos) { + throw(std::runtime_error("No '=' in named argument '"+s+"', this needs to be present for every argument (even if it is empty)")); + } + + std::string name = s.substr(0, pos); + std::string value = s.substr(pos+1); + + if (!rpcCvtTable.convert(strMethod, name)) { + // insert string value directly + params.pushKV(name, value); + } else { + // parse string as JSON, insert bool/number/object/etc. value + params.pushKV(name, ParseNonRFCJSONValue(value)); + } + } + + return params; +} diff --git a/src/rpcclient.h b/src/rpc/rpcclient.h similarity index 71% rename from src/rpcclient.h rename to src/rpc/rpcclient.h index ae015860..f198b96b 100644 --- a/src/rpcclient.h +++ b/src/rpc/rpcclient.h @@ -8,7 +8,11 @@ #include +/** Convert positional arguments to command-specific RPC representation */ UniValue RPCConvertValues(const std::string& strMethod, const std::vector& strParams); +/** Convert named arguments to command-specific RPC representation */ +UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector& strParams); + /** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) * as well as objects and arrays. */ diff --git a/src/rpcdump.cpp b/src/rpc/rpcdump.cpp similarity index 92% rename from src/rpcdump.cpp rename to src/rpc/rpcdump.cpp index 940d5a1f..953a892f 100644 --- a/src/rpcdump.cpp +++ b/src/rpc/rpcdump.cpp @@ -3,15 +3,15 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "base58.h" -#include "chain.h" +#include "chain/chain.h" #include "rpcserver.h" #include "init.h" #include "main.h" #include "script/script.h" #include "script/standard.h" #include "sync.h" -#include "util.h" -#include "utiltime.h" +#include "util/util.h" +#include "util/utiltime.h" #include "wallet/wallet.h" #include @@ -136,7 +136,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp) pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value' if (fRescan) { - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); + pwalletMain->ScanForWalletTransactions(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Genesis(), true); } } @@ -226,7 +226,7 @@ UniValue importaddress(const UniValue& params, bool fHelp) if (fRescan) { - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); + pwalletMain->ScanForWalletTransactions(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Genesis(), true); pwalletMain->ReacceptWalletTransactions(); } @@ -280,7 +280,7 @@ UniValue importpubkey(const UniValue& params, bool fHelp) if (fRescan) { - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); + pwalletMain->ScanForWalletTransactions(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Genesis(), true); pwalletMain->ReacceptWalletTransactions(); } @@ -317,7 +317,7 @@ UniValue importwallet(const UniValue& params, bool fHelp) if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); - int64_t nTimeBegin = chainActive.Tip()->GetBlockTime(); + int64_t nTimeBegin = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockTime(); bool fGood = true; @@ -375,14 +375,14 @@ UniValue importwallet(const UniValue& params, bool fHelp) file.close(); pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI - CBlockIndex *pindex = chainActive.Tip(); + CBlockIndex *pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200) pindex = pindex->pprev; if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey) pwalletMain->nTimeFirstKey = nTimeBegin; - LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1); + LogPrintf("Rescanning last %i blocks\n", pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindex->nHeight + 1); pwalletMain->ScanForWalletTransactions(pindex); pwalletMain->MarkDirty(); @@ -403,7 +403,7 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp) "\nReveals the private key corresponding to 'eccaddress'.\n" "Then the importprivkey can be used with this output\n" "\nArguments:\n" - "1. \"eccaddress\" (string, required) The E-CurrencyCoin address for the private key\n" + "1. \"eccaddress\" (string, required) The ECC address for the private key\n" "\nResult:\n" "\"key\" (string) The private key\n" "\nExamples:\n" @@ -419,7 +419,7 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp) std::string strAddress = params[0].get_str(); CBitcoinAddress address; if (!address.SetString(strAddress)) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid E-CurrencyCoin address"); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid ECC address"); CKeyID keyID; if (!address.GetKeyID(keyID)) throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); @@ -469,10 +469,10 @@ UniValue dumpwallet(const UniValue& params, bool fHelp) std::sort(vKeyBirth.begin(), vKeyBirth.end()); // produce output - file << strprintf("# Wallet dump created by E-CurrencyCoin %s (%s)\n", CLIENT_BUILD, CLIENT_DATE); + file << strprintf("# Wallet dump created by ECC %s (%s)\n", CLIENT_BUILD, CLIENT_DATE); file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime())); - file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString()); - file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime())); + file << strprintf("# * Best block at time of backup was %i (%s),\n", pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height(), pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash().ToString()); + file << strprintf("# mined on %s\n", EncodeDumpTime(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockTime())); file << "\n"; for (std::vector >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { const CKeyID &keyid = it->second; diff --git a/src/rpcmining.cpp b/src/rpc/rpcmining.cpp similarity index 89% rename from src/rpcmining.cpp rename to src/rpc/rpcmining.cpp index 77e9d9ad..f38ff872 100644 --- a/src/rpcmining.cpp +++ b/src/rpc/rpcmining.cpp @@ -4,8 +4,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "amount.h" -#include "chain.h" -#include "chainparams.h" +#include "chain/chain.h" +#include "networks/netman.h" #include "consensus/consensus.h" #include "consensus/validation.h" #include "core_io.h" @@ -16,9 +16,9 @@ #include "pow.h" #include "rpcserver.h" #include "txmempool.h" -#include "util.h" +#include "util/util.h" #include "args.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include "validationinterface.h" #include "processblock.h" #include "processheader.h" @@ -36,17 +36,17 @@ * If 'height' is nonnegative, compute the estimate at the time when a given block was found. */ UniValue GetNetworkHashPS(int lookup, int height) { - CBlockIndex *pb = chainActive.Tip(); + CBlockIndex *pb = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); - if (height >= 0 && height < chainActive.Height()) - pb = chainActive[height]; + if (height >= 0 && height < pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height()) + pb = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive[height]; if (pb == NULL || !pb->nHeight) return 0; // If lookup is -1, then use blocks since last difficulty change. if (lookup <= 0) - lookup = pb->nHeight % Params().GetConsensus().DifficultyAdjustmentInterval() + 1; + lookup = pb->nHeight % pnetMan->getActivePaymentNetwork()->GetConsensus().DifficultyAdjustmentInterval() + 1; // If lookup is larger than chain, then set it to chain length. if (lookup > pb->nHeight) @@ -110,7 +110,7 @@ UniValue getgenerate(const UniValue& params, bool fHelp) ); LOCK(cs_main); - return gArgs.GetBoolArg("-gen", DEFAULT_GENERATE); + return minerThreads != NULL; } UniValue generate(const UniValue& params, bool fHelp) @@ -129,7 +129,7 @@ UniValue generate(const UniValue& params, bool fHelp) + HelpExampleCli("generate", "11") ); - if (!Params().MineBlocksOnDemand()) + if (!pnetMan->getActivePaymentNetwork()->MineBlocksOnDemand()) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); int nHeightStart = 0; @@ -150,7 +150,7 @@ UniValue generate(const UniValue& params, bool fHelp) { // Don't keep cs_main locked LOCK(cs_main); - nHeightStart = chainActive.Height(); + nHeightStart = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height(); nHeight = nHeightStart; nHeightEnd = nHeightStart+nGenerate; } @@ -164,15 +164,15 @@ UniValue generate(const UniValue& params, bool fHelp) CBlock *pblock = &pblocktemplate->block; { LOCK(cs_main); - IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); + IncrementExtraNonce(pblock, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(), nExtraNonce); } - while (pblock->IsProofOfWork() && !CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { + while (pblock->IsProofOfWork() && !CheckProofOfWork(pblock->GetHash(), pblock->nBits, pnetMan->getActivePaymentNetwork()->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. ++pblock->nNonce; } CValidationState state; - if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, GENERATED)) + if (!ProcessNewBlock(state, pnetMan->getActivePaymentNetwork(), NULL, pblock, true, NULL, GENERATED)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); @@ -183,51 +183,29 @@ UniValue generate(const UniValue& params, bool fHelp) return blockHashes; } -/* + UniValue setgenerate(const UniValue& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 2) + if (fHelp || params.size() != 0) throw std::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" + "setgenerate \n" + "\nToggle pos generation on and off with this command.\n" "See the getgenerate call for the current setting.\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" + "None, this will just toggle staking on and off" "\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") + "\nToggle the pos generation\n" + + HelpExampleCli("setgenerate", "") ); - if (Params().MineBlocksOnDemand()) + if (pnetMan->getActivePaymentNetwork()->MineBlocksOnDemand()) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network"); - bool fGenerate = true; - if (params.size() > 0) - fGenerate = params[0].get_bool(); - - int nGenProcLimit = gArgs.GetArg("-genproclimit", DEFAULT_GENERATE_THREADS); - if (params.size() > 1) - { - nGenProcLimit = params[1].get_int(); - if (nGenProcLimit == 0) - fGenerate = false; - } - - gArgs.GetArg("-gen") = (fGenerate ? "1" : "0"); - gArgs.GetArg("-genproclimit") = itostr(nGenProcLimit); - ScryptMiner(fGenerate, nGenProcLimit, Params()); + ThreadScryptMiner(pwalletMain); return NullUniValue; } -*/ + UniValue getmininginfo(const UniValue& params, bool fHelp) { @@ -257,16 +235,15 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) LOCK(cs_main); UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("blocks", (int)chainActive.Height())); + obj.push_back(Pair("blocks", (int)pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height())); obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); 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)gArgs.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("testnet", pnetMan->getActivePaymentNetwork()->TestnetToBeDeprecatedFieldRPC())); + obj.push_back(Pair("chain", pnetMan->getActivePaymentNetwork()->NetworkIDString())); obj.push_back(Pair("generate", getgenerate(params, false))); return obj; } @@ -414,8 +391,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); uint256 hash = block.GetHash(); - BlockMap::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) { + BlockMap::iterator mi = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(hash); + if (mi != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) { CBlockIndex *pindex = mi->second; if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) return "duplicate"; @@ -424,7 +401,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) return "duplicate-inconclusive"; } - CBlockIndex* const pindexPrev = chainActive.Tip(); + CBlockIndex* const pindexPrev = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); // TestBlockValidity only supports blocks built on the current Tip if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; @@ -433,10 +410,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) while(true) { AssertLockHeld(cs_main); - assert(pindexPrev && pindexPrev == chainActive.Tip()); - if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, Params(), block.GetHash())) + assert(pindexPrev && pindexPrev == pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()); + if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, pnetMan->getActivePaymentNetwork(), block.GetHash())) return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str()); - CCoinsViewCache viewNew(pcoinsTip); + CCoinsViewCache viewNew(pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip.get()); CBlockIndex indexDummy(block); indexDummy.pprev = pindexPrev; indexDummy.nHeight = pindexPrev->nHeight + 1; @@ -460,10 +437,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); if (vNodes.empty()) - throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "E-CurrencyCoin is not connected!"); + throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "ECC is not connected!"); - if (IsInitialBlockDownload()) - throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "E-CurrencyCoin is downloading blocks..."); + if (pnetMan->getActivePaymentNetwork()->getChainManager()->IsInitialBlockDownload()) + throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "ECC is downloading blocks..."); static unsigned int nTransactionsUpdatedLast; @@ -485,7 +462,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) else { // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier - hashWatchedChain = chainActive.Tip()->GetBlockHash(); + hashWatchedChain = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash(); nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; } @@ -495,7 +472,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); boost::unique_lock lock(csBestBlock); - while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) + while (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) { if (!cvBlockChange.timed_wait(lock, checktxtime)) { @@ -517,7 +494,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) static CBlockIndex* pindexPrev; static int64_t nStart; static CBlockTemplate* pblocktemplate; - if (pindexPrev != chainActive.Tip() || + if (pindexPrev != pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip() || (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) { // Clear pindexPrev so future calls make a new block, despite any failures from here on @@ -525,7 +502,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) // Store the pindexBest used before CreateNewBlock, to avoid races nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrevNew = chainActive.Tip(); + CBlockIndex* pindexPrevNew = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); nStart = GetTime(); // Create new block @@ -600,7 +577,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("transactions", transactions)); result.push_back(Pair("coinbaseaux", aux)); result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); - result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); + result.push_back(Pair("longpollid", pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); result.push_back(Pair("target", hashTarget.GetHex())); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); result.push_back(Pair("mutable", aMutable)); @@ -661,8 +638,8 @@ UniValue submitblock(const UniValue& params, bool fHelp) bool fBlockPresent = false; { LOCK(cs_main); - BlockMap::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) { + BlockMap::iterator mi = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(hash); + if (mi != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) { CBlockIndex *pindex = mi->second; if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) return "duplicate"; @@ -676,7 +653,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, GENERATED); + bool fAccepted = ProcessNewBlock(state, pnetMan->getActivePaymentNetwork(), NULL, &block, true, NULL, GENERATED); UnregisterValidationInterface(&sc); if (fBlockPresent) { diff --git a/src/rpcmisc.cpp b/src/rpc/rpcmisc.cpp similarity index 83% rename from src/rpcmisc.cpp rename to src/rpc/rpcmisc.cpp index ad761817..9dc65cf3 100644 --- a/src/rpcmisc.cpp +++ b/src/rpc/rpcmisc.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 "args.h" #include "base58.h" #include "clientversion.h" #include "init.h" @@ -12,17 +13,64 @@ #include "netbase.h" #include "rpcserver.h" #include "timedata.h" -#include "util.h" -#include "utilstrencodings.h" +#include "util/util.h" +#include "util/utilstrencodings.h" #include "wallet/wallet.h" #include "wallet/walletdb.h" #include #include +#include #include + +static std::set reloadableSettings = {"-staking", "-rescan"}; + +UniValue reloadconfig (const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + { + throw std::runtime_error( + "reloadconfig\n" + "Returns an object containing the config file arguments that were reloaded.\n" + "The only commands supported for reloading right now are: \n" + "staking \n" + "rescan \n" + ); + } + UniValue obj(UniValue::VOBJ); + + boost::filesystem::ifstream streamConfig(gArgs.GetConfigFile()); + std::set::iterator iter; + std::set processedArgs; + std::set setOptions; + setOptions.insert("*"); + for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) + { + // Don't overwrite existing settings so command line settings override eccoin.conf + std::string strKey = std::string("-") + it->string_key; + std::string strValue = it->value[0]; + InterpretNegativeSetting(strKey, strValue); + iter = reloadableSettings.find(strKey); + if(iter != reloadableSettings.end() && strValue == std::string("1") && processedArgs.find(strKey) != processedArgs.end()) + { + obj.push_back(Pair(strKey, "was reloaded")); + if(strKey == "-staking") + { + ThreadScryptMiner(pwalletMain); + } + if(strKey == "-rescan") + { + pwalletMain->ScanForWalletTransactions(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Genesis(), true); + } + processedArgs.insert(strKey); + } + } + return obj; +} + /** * @note Do not add or change anything in the information returned by this * method. `getinfo` exists for backwards-compatibility only. It combines @@ -47,7 +95,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) " \"version\": xxxxx, (numeric) the server version\n" " \"protocolversion\": xxxxx, (numeric) the protocol version\n" " \"walletversion\": xxxxx, (numeric) the wallet version\n" - " \"balance\": xxxxxxx, (numeric) the total E-CurrencyCoin balance of the wallet\n" + " \"balance\": xxxxxxx, (numeric) the total ECC balance of the wallet\n" " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" " \"timeoffset\": xxxxx, (numeric) the time offset\n" " \"connections\": xxxxx, (numeric) the number of connections\n" @@ -78,15 +126,17 @@ UniValue getinfo(const UniValue& params, bool fHelp) { obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); + obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint()))); + obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake()))); } - obj.push_back(Pair("blocks", (int)chainActive.Height())); - obj.push_back(Pair("headers", (int)pindexBestHeader->nHeight)); - obj.push_back(Pair("moneysupply", ValueFromAmount(chainActive.Tip()->nMoneySupply))); + obj.push_back(Pair("blocks", (int)pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height())); + obj.push_back(Pair("headers", (int)pnetMan->getActivePaymentNetwork()->getChainManager()->pindexBestHeader->nHeight)); + obj.push_back(Pair("moneysupply", ValueFromAmount(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nMoneySupply))); obj.push_back(Pair("timeoffset", GetTimeOffset())); obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string()))); obj.push_back(Pair("difficulty", (double)GetDifficulty())); - obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); + obj.push_back(Pair("testnet", pnetMan->getActivePaymentNetwork()->TestnetToBeDeprecatedFieldRPC())); if (pwalletMain) { obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); @@ -147,13 +197,13 @@ UniValue validateaddress(const UniValue& params, bool fHelp) if (fHelp || params.size() != 1) throw std::runtime_error( "validateaddress \"ecc address\"\n" - "\nReturn information about the given E-CurrencyCoin address.\n" + "\nReturn information about the given ECC address.\n" "\nArguments:\n" "1. \"ecc address\" (string, required) The bitcoin address to validate\n" "\nResult:\n" "{\n" " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" - " \"address\" : \"ecc address\", (string) The E-CurrencyCoin address validated\n" + " \"address\" : \"ecc address\", (string) The ECC address validated\n" " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n" " \"ismine\" : true|false, (boolean) If the address is yours or not\n" " \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n" @@ -216,7 +266,7 @@ CScript _createmultisig_redeemScript(const UniValue& params) for (unsigned int i = 0; i < keys.size(); i++) { const std::string& ks = keys[i].get_str(); - // Case 1: E-CurrencyCoin address and we have full public key: + // Case 1: ECC address and we have full public key: CBitcoinAddress address(ks); if (pwalletMain && address.IsValid()) { @@ -266,9 +316,9 @@ UniValue createmultisig(const UniValue& params, bool fHelp) "\nArguments:\n" "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" - "2. \"keys\" (string, required) A json array of keys which are E-CurrencyCoin addresses or hex-encoded public keys\n" + "2. \"keys\" (string, required) A json array of keys which are ECC addresses or hex-encoded public keys\n" " [\n" - " \"key\" (string) E-CurrencyCoin address or hex-encoded public key\n" + " \"key\" (string) ECC address or hex-encoded public key\n" " ,...\n" " ]\n" @@ -306,7 +356,7 @@ UniValue verifymessage(const UniValue& params, bool fHelp) "verifymessage \"ecc address\" \"signature\" \"message\"\n" "\nVerify a signed message\n" "\nArguments:\n" - "1. \"ecc address\" (string, required) The E-CurrencyCoin address to use for the signature.\n" + "1. \"ecc address\" (string, required) The ECC address to use for the signature.\n" "2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n" "3. \"message\" (string, required) The message that was signed.\n" "\nResult:\n" @@ -364,7 +414,7 @@ UniValue setmocktime(const UniValue& params, bool fHelp) " Pass 0 to go back to using the system time." ); - if (!Params().MineBlocksOnDemand()) + if (!pnetMan->getActivePaymentNetwork()->MineBlocksOnDemand()) throw std::runtime_error("setmocktime for regression testing (-regtest mode) only"); // cs_vNodes is locked and node send/receive times are updated diff --git a/src/rpcnet.cpp b/src/rpc/rpcnet.cpp similarity index 99% rename from src/rpcnet.cpp rename to src/rpc/rpcnet.cpp index a753b5b7..fc589ef2 100644 --- a/src/rpcnet.cpp +++ b/src/rpc/rpcnet.cpp @@ -4,7 +4,7 @@ #include "rpcserver.h" -#include "chainparams.h" +#include "networks/netman.h" #include "clientversion.h" #include "main.h" #include "net.h" @@ -13,10 +13,12 @@ #include "sync.h" #include "timedata.h" #include "ui_interface.h" -#include "util.h" -#include "utilstrencodings.h" +#include "util/util.h" +#include "util/utilstrencodings.h" #include "version.h" +#include "init.h" + #include UniValue getconnectioncount(const UniValue& params, bool fHelp) @@ -310,7 +312,7 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) std::list > > laddedAddreses(0); for (auto const& strAddNode: laddedNodes) { std::vector vservNode(0); - if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) + if(Lookup(strAddNode.c_str(), vservNode, pnetMan->getActivePaymentNetwork()->GetDefaultPort(), fNameLookup, 0)) laddedAddreses.push_back(std::make_pair(strAddNode, vservNode)); else { diff --git a/src/rpcprotocol.cpp b/src/rpc/rpcprotocol.cpp similarity index 79% rename from src/rpcprotocol.cpp rename to src/rpc/rpcprotocol.cpp index 6b7076e5..f069f5e1 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpc/rpcprotocol.cpp @@ -7,10 +7,10 @@ #include "random.h" #include "tinyformat.h" -#include "util.h" +#include "util/util.h" #include "args.h" -#include "utilstrencodings.h" -#include "utiltime.h" +#include "util/utilstrencodings.h" +#include "util/utiltime.h" #include "version.h" #include @@ -25,6 +25,15 @@ * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html */ +UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id) +{ + UniValue request(UniValue::VOBJ); + request.push_back(Pair("method", strMethod)); + request.push_back(Pair("params", params)); + request.push_back(Pair("id", id)); + return request; +} + std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id) { UniValue request(UniValue::VOBJ); @@ -124,3 +133,22 @@ void DeleteAuthCookie() } } +std::vector JSONRPCProcessBatchReply(const UniValue &in, size_t num) +{ + if (!in.isArray()) { + throw std::runtime_error("Batch must be an array"); + } + std::vector batch(num); + for (size_t i=0; i= num) { + throw std::runtime_error("Batch member id larger than size"); + } + batch[id] = rec; + } + return batch; +} diff --git a/src/rpcprotocol.h b/src/rpc/rpcprotocol.h similarity index 95% rename from src/rpcprotocol.h rename to src/rpc/rpcprotocol.h index 55d0aac6..c9e4fa62 100644 --- a/src/rpcprotocol.h +++ b/src/rpc/rpcprotocol.h @@ -76,6 +76,7 @@ enum RPCErrorCode RPC_WALLET_ALREADY_UNLOCKED = -17, //! Wallet is already unlocked }; +UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id); std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id); UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id); std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id); @@ -89,5 +90,7 @@ bool GenerateAuthCookie(std::string *cookie_out); bool GetAuthCookie(std::string *cookie_out); /** Delete RPC authentication cookie from disk */ void DeleteAuthCookie(); +/** Parse JSON-RPC batch reply into a vector */ +std::vector JSONRPCProcessBatchReply(const UniValue &in, size_t num); #endif // BITCOIN_RPCPROTOCOL_H diff --git a/src/rpcrawtransaction.cpp b/src/rpc/rpcrawtransaction.cpp similarity index 93% rename from src/rpcrawtransaction.cpp rename to src/rpc/rpcrawtransaction.cpp index 5a31ebf2..ce80a549 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpc/rpcrawtransaction.cpp @@ -4,7 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "base58.h" -#include "chain.h" +#include "chain/chain.h" #include "coins.h" #include "consensus/validation.h" #include "core_io.h" @@ -14,7 +14,7 @@ #include "merkleblock.h" #include "net.h" #include "policy/policy.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include "rpcserver.h" #include "script/script.h" #include "script/script_error.h" @@ -22,7 +22,7 @@ #include "script/standard.h" #include "txmempool.h" #include "uint256.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include "wallet/wallet.h" #include @@ -93,11 +93,11 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) if (!hashBlock.IsNull()) { entry.push_back(Pair("blockhash", hashBlock.GetHex())); - BlockMap::iterator mi = mapBlockIndex.find(hashBlock); - if (mi != mapBlockIndex.end() && (*mi).second) { + BlockMap::iterator mi = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(hashBlock); + if (mi != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end() && (*mi).second) { CBlockIndex* pindex = (*mi).second; - if (chainActive.Contains(pindex)) { - entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight)); + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(pindex)) { + entry.push_back(Pair("confirmations", 1 + pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindex->nHeight)); entry.push_back(Pair("time", pindex->GetBlockTime())); entry.push_back(Pair("blocktime", pindex->GetBlockTime())); } @@ -155,7 +155,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) " \"reqSigs\" : n, (numeric) The required sigs\n" " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" " \"addresses\" : [ (json array of string)\n" - " \"ecc address\" (string) E-CurrencyCoin address\n" + " \"ecc address\" (string) ECC address\n" " ,...\n" " ]\n" " }\n" @@ -184,7 +184,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) CTransaction tx; uint256 hashBlock; - if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) + if (!GetTransaction(hash, tx, pnetMan->getActivePaymentNetwork()->GetConsensus(), hashBlock, true)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); std::string strHex = EncodeHexTx(tx); @@ -242,27 +242,27 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp) if (params.size() > 1) { hashBlock = uint256S(params[1].get_str()); - if (!mapBlockIndex.count(hashBlock)) + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(hashBlock)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - pblockindex = mapBlockIndex[hashBlock]; + pblockindex = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[hashBlock]; } else { CCoins coins; - if (pcoinsTip->GetCoins(oneTxid, coins) && coins.nHeight > 0 && coins.nHeight <= chainActive.Height()) - pblockindex = chainActive[coins.nHeight]; + if (pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->GetCoins(oneTxid, coins) && coins.nHeight > 0 && coins.nHeight <= pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height()) + pblockindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive[coins.nHeight]; } if (pblockindex == NULL) { CTransaction tx; - if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull()) + if (!GetTransaction(oneTxid, tx, pnetMan->getActivePaymentNetwork()->GetConsensus(), hashBlock, false) || hashBlock.IsNull()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); - if (!mapBlockIndex.count(hashBlock)) + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(hashBlock)) throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); - pblockindex = mapBlockIndex[hashBlock]; + pblockindex = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[hashBlock]; } CBlock block; - if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) + if(!ReadBlockFromDisk(block, pblockindex, pnetMan->getActivePaymentNetwork()->GetConsensus())) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); unsigned int ntxFound = 0; @@ -304,7 +304,7 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp) LOCK(cs_main); - if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()])) + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(merkleBlock.header.GetHash()) || !pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[merkleBlock.header.GetHash()])) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); for (auto const& hash: vMatch) @@ -334,7 +334,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) " ]\n" "2. \"outputs\" (string, required) a json object with outputs\n" " {\n" - " \"address\": x.xxx (numeric or string, required) The key is the E-CurrencyCoin address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n" + " \"address\": x.xxx (numeric or string, required) The key is the ECC address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n" " \"data\": \"hex\", (string, required) The key is \"data\", the value is hex encoded data\n" " ...\n" " }\n" @@ -397,7 +397,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) } else { CBitcoinAddress address(name_); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid E-CurrencyCoin address: ")+name_); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid ECC address: ")+name_); if (setAddress.count(address)) throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_); @@ -452,7 +452,7 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp) " \"reqSigs\" : n, (numeric) The required sigs\n" " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" " \"addresses\" : [ (json array of string)\n" - " \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) E-CurrencyCoin address\n" + " \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) ECC address\n" " ,...\n" " ]\n" " }\n" @@ -495,7 +495,7 @@ UniValue decodescript(const UniValue& params, bool fHelp) " \"type\":\"type\", (string) The output type\n" " \"reqSigs\": n, (numeric) The required signatures\n" " \"addresses\": [ (json array of string)\n" - " \"address\" (string) E-CurrencyCoin address\n" + " \"address\" (string) ECC address\n" " ,...\n" " ],\n" " \"p2sh\",\"address\" (string) script address\n" @@ -620,7 +620,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) CCoinsViewCache view(&viewDummy); { LOCK(mempool.cs); - CCoinsViewCache &viewChain = *pcoinsTip; + CCoinsViewCache &viewChain = *pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip; CCoinsViewMemPool viewMempool(&viewChain, mempool); view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view @@ -799,7 +799,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) if (params.size() > 1) fOverrideFees = params[1].get_bool(); - CCoinsViewCache &view = *pcoinsTip; + CCoinsViewCache &view = *pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip; const CCoins* existingCoins = view.AccessCoins(hashTx); bool fHaveMempool = mempool.exists(hashTx); bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000; diff --git a/src/rpcserver.cpp b/src/rpc/rpcserver.cpp similarity index 62% rename from src/rpcserver.cpp rename to src/rpc/rpcserver.cpp index 8968e9ea..35d2bc6f 100644 --- a/src/rpcserver.cpp +++ b/src/rpc/rpcserver.cpp @@ -12,39 +12,48 @@ #include "random.h" #include "sync.h" #include "ui_interface.h" -#include "util.h" +#include "util/util.h" #include "args.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" + +#include +#include +#include "events.h" #include -#include -#include -#include -#include -#include -#include -#include -#include // for to_upper() - -#include -#include -#include -#include -#include -#include +#include + +static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; +static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; +static const bool DEFAULT_NAMED=false; +static const int CONTINUE_EXECUTION=-1; using namespace RPCServer; -static bool fRPCRunning = false; -static bool fRPCInWarmup = true; -static std::string rpcWarmupStatus("RPC server started"); -static CCriticalSection cs_rpcWarmup; +bool fRPCRunning = false; +bool fRPCInWarmup = true; +std::string rpcWarmupStatus("RPC server started"); +CCriticalSection cs_rpcWarmup; /* Timer-creating functions */ -static std::vector timerInterfaces; +std::vector timerInterfaces; /* Map of name to timer. * @note Can be changed to std::unique_ptr when C++11 */ -static std::map > deadlineTimers; +std::map > deadlineTimers; + +// +// Exception thrown on connection error. This error is used to determine +// when to wait if -rpcwait is given. +// +class CConnectionFailed : public std::runtime_error +{ +public: + + explicit inline CConnectionFailed(const std::string& msg) : + std::runtime_error(msg) + {} + +}; static struct CRPCSignals { @@ -275,11 +284,11 @@ UniValue stop(const UniValue& params, bool fHelp) if (fHelp || params.size() > 1) throw std::runtime_error( "stop\n" - "\nStop E-CurrencyCoin server."); + "\nStop ECC server."); // Event loop will exit after current HTTP requests have been handled, so // this reply will get back to the client. StartShutdown(); - return "E-CurrencyCoin server stopping"; + return "ECC server stopping"; } /** @@ -332,7 +341,7 @@ static const CRPCCommand vRPCCommands[] = /* Coin generation */ { "generating", "getgenerate", &getgenerate, true }, - //{ "generating", "setgenerate", &setgenerate, true }, + { "generating", "setgenerate", &setgenerate, true }, { "generating", "generate", &generate, true }, /* Raw transactions */ @@ -597,242 +606,343 @@ void RPCRunLater(const std::string& name, boost::function func, int6 deadlineTimers.insert(std::make_pair(name, boost::shared_ptr(timerInterface->NewTimer(func, nSeconds*1000)))); } -// -// IOStream device that speaks SSL but can also speak non-SSL -// -template -class SSLIOStreamDevice : public boost::iostreams::device { -public: - SSLIOStreamDevice(boost::asio::ssl::stream &streamIn, bool fUseSSLIn) : stream(streamIn) - { - fUseSSL = fUseSSLIn; - fNeedHandshake = fUseSSLIn; - } - - void handshake(boost::asio::ssl::stream_base::handshake_type role) - { - if (!fNeedHandshake) return; - fNeedHandshake = false; - stream.handshake(role); - } - std::streamsize read(char* s, std::streamsize n) - { - handshake(boost::asio::ssl::stream_base::server); // HTTPS servers read first - if (fUseSSL) return stream.read_some(boost::asio::buffer(s, n)); - return stream.next_layer().read_some(boost::asio::buffer(s, n)); - } - std::streamsize write(const char* s, std::streamsize n) - { - handshake(boost::asio::ssl::stream_base::client); // HTTPS clients write first - if (fUseSSL) return boost::asio::write(stream, boost::asio::buffer(s, n)); - return boost::asio::write(stream.next_layer(), boost::asio::buffer(s, n)); - } - bool connect(const std::string& server, const std::string& port) - { - boost::asio::ip::tcp::resolver resolver(stream.get_io_service()); - boost::asio::ip::tcp::resolver::query query(server.c_str(), port.c_str()); - boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); - boost::asio::ip::tcp::resolver::iterator end; - boost::system::error_code error = boost::asio::error::host_not_found; - while (error && endpoint_iterator != end) - { - stream.lowest_layer().close(); - stream.lowest_layer().connect(*endpoint_iterator++, error); - } - if (error) - return false; - return true; - } +/** Reply structure for request_done to fill in */ +struct HTTPReply +{ + HTTPReply(): status(0), error(-1) {} -private: - bool fNeedHandshake; - bool fUseSSL; - boost::asio::ssl::stream& stream; + int status; + int error; + std::string body; }; -std::string HTTPPost(const std::string& strMsg, const std::map& mapRequestHeaders) -{ - std::ostringstream s; - s << "POST / HTTP/1.1\r\n" - << "User-Agent: eccoin-json-rpc/" << FormatFullVersion() << "\r\n" - << "Host: 127.0.0.1\r\n" - << "Content-Type: application/json\r\n" - << "Content-Length: " << strMsg.size() << "\r\n" - << "Connection: close\r\n" - << "Accept: application/json\r\n"; - for (auto const& item: mapRequestHeaders) - s << item.first << ": " << item.second << "\r\n"; - s << "\r\n" << strMsg; - - return s.str(); +const char *http_errorstring(int code) +{ + switch(code) { +#if LIBEVENT_VERSION_NUMBER >= 0x02010300 + case EVREQ_HTTP_TIMEOUT: + return "timeout reached"; + case EVREQ_HTTP_EOF: + return "EOF reached"; + case EVREQ_HTTP_INVALID_HEADER: + return "error while reading header, or invalid header"; + case EVREQ_HTTP_BUFFER_ERROR: + return "error encountered while reading or writing"; + case EVREQ_HTTP_REQUEST_CANCEL: + return "request was canceled"; + case EVREQ_HTTP_DATA_TOO_LONG: + return "response body is larger than allowed"; +#endif + default: + return "unknown"; + } } -std::string rfc1123Time() +static void http_request_done(struct evhttp_request *req, void *ctx) { - char buffer[64]; - time_t now; - time(&now); - struct tm* now_gmt = gmtime(&now); - std::string locale(setlocale(LC_TIME, NULL)); - setlocale(LC_TIME, "C"); // we want POSIX (aka "C") weekday/month strings - strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt); - setlocale(LC_TIME, locale.c_str()); - return std::string(buffer); -} + HTTPReply *reply = static_cast(ctx); -int ReadHTTPStatus(std::basic_istream& stream, int &proto) -{ - std::string str; - getline(stream, str); - std::vector vWords; - boost::split(vWords, str, boost::is_any_of(" ")); - if (vWords.size() < 2) - return HTTP_INTERNAL_SERVER_ERROR; - proto = 0; - const char *ver = strstr(str.c_str(), "HTTP/1."); - if (ver != NULL) - proto = atoi(ver+7); - return atoi(vWords[1].c_str()); -} + if (req == nullptr) { + /* If req is nullptr, it means an error occurred while connecting: the + * error code will have been passed to http_error_cb. + */ + reply->status = 0; + return; + } -int ReadHTTPHeader(std::basic_istream& stream, std::map& mapHeadersRet) -{ - int nLen = 0; - while (true) + reply->status = evhttp_request_get_response_code(req); + + struct evbuffer *buf = evhttp_request_get_input_buffer(req); + if (buf) { - std::string str; - std::getline(stream, str); - if (str.empty() || str == "\r") - break; - std::string::size_type nColon = str.find(":"); - if (nColon != std::string::npos) - { - std::string strHeader = str.substr(0, nColon); - boost::trim(strHeader); - boost::to_lower(strHeader); - std::string strValue = str.substr(nColon+1); - boost::trim(strValue); - mapHeadersRet[strHeader] = strValue; - if (strHeader == "content-length") - nLen = atoi(strValue.c_str()); - } + size_t size = evbuffer_get_length(buf); + const char *data = (const char*)evbuffer_pullup(buf, size); + if (data) + reply->body = std::string(data, size); + evbuffer_drain(buf, size); } - return nLen; } -int ReadHTTP(std::basic_istream& stream, std::map& mapHeadersRet, std::string& strMessageRet) +#if LIBEVENT_VERSION_NUMBER >= 0x02010300 +static void http_error_cb(enum evhttp_request_error err, void *ctx) { - mapHeadersRet.clear(); - strMessageRet = ""; + HTTPReply *reply = static_cast(ctx); + reply->error = err; +} +#endif - // Read status - int nProto = 0; - int nStatus = ReadHTTPStatus(stream, nProto); +/** Class that handles the conversion from a command-line to a JSON-RPC request, + * as well as converting back to a JSON object that can be shown as result. + */ +class BaseRequestHandler +{ +public: + virtual UniValue PrepareRequest(const std::string& method, const std::vector& args) = 0; + virtual UniValue ProcessReply(const UniValue &batch_in) = 0; +}; - // Read header - int nLen = ReadHTTPHeader(stream, mapHeadersRet); - if (nLen < 0 || nLen > (int)MAX_SIZE) - return HTTP_INTERNAL_SERVER_ERROR; +/** Process getinfo requests */ +class GetinfoRequestHandler: public BaseRequestHandler +{ +public: + const int ID_NETWORKINFO = 0; + const int ID_BLOCKCHAININFO = 1; + const int ID_WALLETINFO = 2; - // Read message - if (nLen > 0) + /** Create a simulated `getinfo` request. */ + UniValue PrepareRequest(const std::string& method, const std::vector& args) override { - std::vector vch(nLen); - stream.read(&vch[0], nLen); - strMessageRet = std::string(vch.begin(), vch.end()); + if (!args.empty()) { + throw std::runtime_error("-getinfo takes no arguments"); + } + UniValue result(UniValue::VARR); + result.push_back(JSONRPCRequestObj("getnetworkinfo", NullUniValue, ID_NETWORKINFO)); + result.push_back(JSONRPCRequestObj("getblockchaininfo", NullUniValue, ID_BLOCKCHAININFO)); + result.push_back(JSONRPCRequestObj("getwalletinfo", NullUniValue, ID_WALLETINFO)); + return result; } - std::string sConHdr = mapHeadersRet["connection"]; - - if ((sConHdr != "close") && (sConHdr != "keep-alive")) + /** Collect values from the batch and form a simulated `getinfo` reply. */ + UniValue ProcessReply(const UniValue &batch_in) override { - if (nProto >= 1) - mapHeadersRet["connection"] = "keep-alive"; - else - mapHeadersRet["connection"] = "close"; + UniValue result(UniValue::VOBJ); + std::vector batch = JSONRPCProcessBatchReply(batch_in, 3); + // Errors in getnetworkinfo() and getblockchaininfo() are fatal, pass them on + // getwalletinfo() is allowed to fail in case there is no wallet. + if (!batch[ID_NETWORKINFO]["error"].isNull()) { + return batch[ID_NETWORKINFO]; + } + if (!batch[ID_BLOCKCHAININFO]["error"].isNull()) { + return batch[ID_BLOCKCHAININFO]; + } + result.pushKV("version", batch[ID_NETWORKINFO]["result"]["version"]); + result.pushKV("protocolversion", batch[ID_NETWORKINFO]["result"]["protocolversion"]); + if (!batch[ID_WALLETINFO].isNull()) { + result.pushKV("walletversion", batch[ID_WALLETINFO]["result"]["walletversion"]); + result.pushKV("balance", batch[ID_WALLETINFO]["result"]["balance"]); + } + result.pushKV("blocks", batch[ID_BLOCKCHAININFO]["result"]["blocks"]); + result.pushKV("timeoffset", batch[ID_NETWORKINFO]["result"]["timeoffset"]); + result.pushKV("connections", batch[ID_NETWORKINFO]["result"]["connections"]); + result.pushKV("proxy", batch[ID_NETWORKINFO]["result"]["networks"][0]["proxy"]); + result.pushKV("difficulty", batch[ID_BLOCKCHAININFO]["result"]["difficulty"]); + result.pushKV("testnet", UniValue(batch[ID_BLOCKCHAININFO]["result"]["chain"].get_str() == "test")); + if (!batch[ID_WALLETINFO].isNull()) { + result.pushKV("walletversion", batch[ID_WALLETINFO]["result"]["walletversion"]); + result.pushKV("balance", batch[ID_WALLETINFO]["result"]["balance"]); + result.pushKV("keypoololdest", batch[ID_WALLETINFO]["result"]["keypoololdest"]); + result.pushKV("keypoolsize", batch[ID_WALLETINFO]["result"]["keypoolsize"]); + if (!batch[ID_WALLETINFO]["result"]["unlocked_until"].isNull()) { + result.pushKV("unlocked_until", batch[ID_WALLETINFO]["result"]["unlocked_until"]); + } + result.pushKV("paytxfee", batch[ID_WALLETINFO]["result"]["paytxfee"]); + } + result.pushKV("relayfee", batch[ID_NETWORKINFO]["result"]["relayfee"]); + result.pushKV("warnings", batch[ID_NETWORKINFO]["result"]["warnings"]); + return JSONRPCReplyObj(result, NullUniValue, 1); } +}; - return nStatus; -} +/** Process default single requests */ +class DefaultRequestHandler: public BaseRequestHandler { +public: + UniValue PrepareRequest(const std::string& method, const std::vector& args) override + { + UniValue params; + if(gArgs.GetBoolArg("-named", DEFAULT_NAMED)) { + params = RPCConvertNamedValues(method, args); + } else { + params = RPCConvertValues(method, args); + } + return JSONRPCRequestObj(method, params, 1); + } -static inline unsigned short GetDefaultRPCPort() -{ - return gArgs.GetBoolArg("-testnet", false) ? 29119 : 19119; -} + UniValue ProcessReply(const UniValue &reply) override + { + return reply.get_obj(); + } +}; -UniValue CallRPC(const std::string& strMethod, const UniValue& params) -{ - if (gArgs.GetArg("-rpcuser","") == "" && gArgs.GetArg("-rpcpassword","") == "") - throw std::runtime_error(strprintf( - _("You must set rpcpassword= in the configuration file:\n%s\n" - "If the file does not exist, create it with owner-readable-only file permissions."), - gArgs.GetConfigFile().string().c_str())); +static UniValue CallRPC(BaseRequestHandler *rh, const std::string& strMethod, const std::vector& args) +{ + std::string host; + // In preference order, we choose the following for the port: + // 1. -rpcport + // 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6) + // 3. default port for chain + int port = RPCPortFromCommandLine(); + SplitHostPort(gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT), port, host); + port = gArgs.GetArg("-rpcport", port); + + // Obtain event base + raii_event_base base = obtain_event_base(); + + // Synchronously look up hostname + raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port); + evhttp_connection_set_timeout(evcon.get(), gArgs.GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT)); + + HTTPReply response; + raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response); + if (req == nullptr) + throw std::runtime_error("create http request failed"); +#if LIBEVENT_VERSION_NUMBER >= 0x02010300 + evhttp_request_set_error_cb(req.get(), http_error_cb); +#endif + + // Get credentials + std::string strRPCUserColonPass; + if (gArgs.GetArg("-rpcpassword", "") == "") { + // Try fall back to cookie-based authentication if no password is provided + if (!GetAuthCookie(&strRPCUserColonPass)) { + throw std::runtime_error(strprintf( + _("Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)"), + gArgs.GetConfigFile().string().c_str())); - // Connect to localhost - bool fUseSSL = gArgs.GetBoolArg("-rpcssl", false); // Check this - boost::asio::io_service io_service; - boost::asio::ssl::context context(io_service, boost::asio::ssl::context::sslv23); - context.set_options(boost::asio::ssl::context::no_sslv2); - boost::asio::ssl::stream sslStream(io_service, context); - SSLIOStreamDevice d(sslStream, fUseSSL); - boost::iostreams::stream< SSLIOStreamDevice > stream(d); - if (!d.connect(gArgs.GetArg("-rpcconnect", "127.0.0.1"), gArgs.GetArg("-rpcport", itostr(GetDefaultRPCPort())))) - throw std::runtime_error("couldn't connect to server"); + } + } else { + strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", ""); + } - // HTTP basic authentication - std::string strUserPass64 = EncodeBase64(gArgs.GetArg("-rpcuser","") + ":" + gArgs.GetArg("-rpcpassword","")); - std::map mapRequestHeaders; - mapRequestHeaders["Authorization"] = std::string("Basic ") + strUserPass64; + struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get()); + assert(output_headers); + evhttp_add_header(output_headers, "Host", host.c_str()); + evhttp_add_header(output_headers, "Connection", "close"); + evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str()); + + // Attach request data + std::string strRequest = rh->PrepareRequest(strMethod, args).write() + "\n"; + struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get()); + assert(output_buffer); + evbuffer_add(output_buffer, strRequest.data(), strRequest.size()); + + // check if we should use a special wallet endpoint + std::string endpoint = "/"; + std::string walletName = gArgs.GetArg("-rpcwallet", ""); + if (!walletName.empty()) { + char *encodedURI = evhttp_uriencode(walletName.c_str(), walletName.size(), false); + if (encodedURI) { + endpoint = "/wallet/"+ std::string(encodedURI); + free(encodedURI); + } + else { + throw CConnectionFailed("uri-encode failed"); + } + } + int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, endpoint.c_str()); + req.release(); // ownership moved to evcon in above call + if (r != 0) { + throw CConnectionFailed("send http request failed"); + } - // Send request - std::string strRequest = JSONRPCRequest(strMethod, params, 1); - std::string strPost = HTTPPost(strRequest, mapRequestHeaders); - stream << strPost << std::flush; + event_base_dispatch(base.get()); - // Receive reply - std::map mapHeaders; - std::string strReply; - int nStatus = ReadHTTP(stream, mapHeaders, strReply); - if (nStatus == HTTP_UNAUTHORIZED) + if (response.status == 0) + throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error)); + else if (response.status == HTTP_UNAUTHORIZED) throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); - else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR) - throw std::runtime_error(strprintf("server returned HTTP error %d", nStatus)); - else if (strReply.empty()) + else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) + throw std::runtime_error(strprintf("server returned HTTP error %d", response.status)); + else if (response.body.empty()) throw std::runtime_error("no response from server"); // Parse reply - UniValue valReply; - if (!valReply.setStr(strReply)) + UniValue valReply(UniValue::VSTR); + if (!valReply.read(response.body)) throw std::runtime_error("couldn't parse reply from server"); + const UniValue reply = rh->ProcessReply(valReply); + if (reply.empty()) + throw std::runtime_error("expected reply to have result, error and id properties"); - return valReply; + return reply; } int CommandLineRPC(int argc, char *argv[]) { std::string strPrint; int nRet = 0; - try - { + try { // Skip switches - while (argc > 1 && IsSwitchChar(argv[1][0])) - { + while (argc > 1 && IsSwitchChar(argv[1][0])) { argc--; argv++; } + std::string rpcPass; + if (gArgs.GetBoolArg("-stdinrpcpass", false)) { + if (!std::getline(std::cin, rpcPass)) { + throw std::runtime_error("-stdinrpcpass specified but failed to read from standard input"); + } + gArgs.ForceSetArg("-rpcpassword", rpcPass); + } + std::vector args = std::vector(&argv[1], &argv[argc]); + if (gArgs.GetBoolArg("-stdin", false)) { + // Read one arg per line from stdin and append + std::string line; + while (std::getline(std::cin, line)) { + args.push_back(line); + } + } + std::unique_ptr rh; + std::string method; + if (gArgs.GetBoolArg("-getinfo", false)) { + rh.reset(new GetinfoRequestHandler()); + method = ""; + } else { + rh.reset(new DefaultRequestHandler()); + if (args.size() < 1) { + throw std::runtime_error("too few parameters (need at least command)"); + } + method = args[0]; + args.erase(args.begin()); // Remove trailing method name from arguments vector + } - // Method - if (argc < 2) - throw std::runtime_error("too few parameters"); - std::string strMethod = argv[1]; - - // Parameters default to strings - std::vector strParams(&argv[2], &argv[argc]); - UniValue params = RPCConvertValues(strMethod, strParams); - - // Execute - UniValue reply = CallRPC(strMethod, params); - strPrint = reply.get_str(); + // Execute and handle connection failures with -rpcwait + const bool fWait = gArgs.GetBoolArg("-rpcwait", false); + do { + try { + const UniValue reply = CallRPC(rh.get(), method, args); + + // Parse reply + const UniValue& result = find_value(reply, "result"); + const UniValue& error = find_value(reply, "error"); + + if (!error.isNull()) { + // Error + int code = error["code"].get_int(); + if (fWait && code == RPC_IN_WARMUP) + throw CConnectionFailed("server in warmup"); + strPrint = "error: " + error.write(); + nRet = abs(code); + if (error.isObject()) + { + UniValue errCode = find_value(error, "code"); + UniValue errMsg = find_value(error, "message"); + strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n"; + + if (errMsg.isStr()) + strPrint += "error message:\n"+errMsg.get_str(); + } + } else { + // Result + if (result.isNull()) + strPrint = ""; + else if (result.isStr()) + strPrint = result.get_str(); + else + strPrint = result.write(2); + } + // Connection succeeded, no need to retry. + break; + } + catch (const CConnectionFailed&) { + if (fWait) + MilliSleep(1000); + else + throw; + } + } while (fWait); + } + catch (const boost::thread_interrupted&) { + throw; } catch (std::exception& e) { @@ -846,7 +956,7 @@ int CommandLineRPC(int argc, char *argv[]) if (strPrint != "") { - fprintf((nRet == 0 ? stdout : stderr), "%s\n", ParseJson(strPrint.c_str()).c_str()); + fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str()); } return nRet; } diff --git a/src/rpcserver.h b/src/rpc/rpcserver.h similarity index 99% rename from src/rpcserver.h rename to src/rpc/rpcserver.h index e511baac..c01c39a9 100644 --- a/src/rpcserver.h +++ b/src/rpc/rpcserver.h @@ -184,7 +184,7 @@ extern UniValue dumpwallet(const UniValue& params, bool fHelp); extern UniValue importwallet(const UniValue& params, bool fHelp); extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpcmining.cpp -//extern UniValue setgenerate(const UniValue& params, bool fHelp); +extern UniValue setgenerate(const UniValue& params, bool fHelp); extern UniValue generate(const UniValue& params, bool fHelp); extern UniValue getnetworkhashps(const UniValue& params, bool fHelp); extern UniValue getmininginfo(const UniValue& params, bool fHelp); diff --git a/src/rpcwallet.cpp b/src/rpc/rpcwallet.cpp similarity index 98% rename from src/rpcwallet.cpp rename to src/rpc/rpcwallet.cpp index 7d9471fd..f32d9d96 100644 --- a/src/rpcwallet.cpp +++ b/src/rpc/rpcwallet.cpp @@ -5,7 +5,7 @@ #include "amount.h" #include "base58.h" -#include "chain.h" +#include "chain/chain.h" #include "core_io.h" #include "init.h" #include "main.h" @@ -14,8 +14,8 @@ #include "policy/rbf.h" #include "rpcserver.h" #include "timedata.h" -#include "util.h" -#include "utilmoneystr.h" +#include "util/util.h" +#include "util/utilmoneystr.h" #include "wallet/wallet.h" #include "wallet/walletdb.h" @@ -65,7 +65,7 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) { entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); entry.push_back(Pair("blockindex", wtx.nIndex)); - entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime())); + entry.push_back(Pair("blocktime", pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[wtx.hashBlock]->GetBlockTime())); } else { entry.push_back(Pair("trusted", wtx.IsTrusted())); } @@ -143,7 +143,6 @@ UniValue getnewaddress(const UniValue& params, bool fHelp) CKeyID keyID = newKey.GetID(); pwalletMain->SetAddressBook(keyID, strAccount, "receive"); - return CBitcoinAddress(keyID).ToString(); } @@ -662,7 +661,7 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp) for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; - if (wtx.IsCoinBase() || !CheckFinalTx(wtx)) + if (wtx.IsCoinBase() || wtx.IsCoinStake() || !CheckFinalTx(wtx)) continue; for (auto const& txout: wtx.vout) @@ -1138,7 +1137,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) { const CWalletTx& wtx = (*it).second; - if (wtx.IsCoinBase() || !CheckFinalTx(wtx)) + if (wtx.IsCoinBase() || wtx.IsCoinStake() || !CheckFinalTx(wtx)) continue; int nDepth = wtx.GetDepthInMainChain(); @@ -1355,6 +1354,7 @@ void ListTransactions(const CWalletTx& wtx, const std::string& strAccount, int n // Received if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) { + bool stop = false; for (auto const& r: listReceived) { std::string account; @@ -1367,7 +1367,7 @@ void ListTransactions(const CWalletTx& wtx, const std::string& strAccount, int n entry.push_back(Pair("involvesWatchonly", true)); entry.push_back(Pair("account", account)); MaybePushAddress(entry, r.destination); - if (wtx.IsCoinBase()) + if (wtx.IsCoinBase() || wtx.IsCoinStake()) { if (wtx.GetDepthInMainChain() < 1) entry.push_back(Pair("category", "orphan")); @@ -1380,7 +1380,13 @@ void ListTransactions(const CWalletTx& wtx, const std::string& strAccount, int n { entry.push_back(Pair("category", "receive")); } - entry.push_back(Pair("amount", ValueFromAmount(r.amount))); + if (!wtx.IsCoinStake()) + entry.push_back(Pair("amount", ValueFromAmount(r.amount))); + else + { + entry.push_back(Pair("amount", ValueFromAmount(-nFee))); + stop = true; // only one coinstake output + } if (pwalletMain->mapAddressBook.count(r.destination)) entry.push_back(Pair("label", account)); entry.push_back(Pair("vout", r.vout)); @@ -1388,6 +1394,10 @@ void ListTransactions(const CWalletTx& wtx, const std::string& strAccount, int n WalletTxToJSON(wtx, entry); ret.push_back(entry); } + if(stop) + { + break; + } } } } @@ -1667,8 +1677,8 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) uint256 blockId; blockId.SetHex(params[0].get_str()); - BlockMap::iterator it = mapBlockIndex.find(blockId); - if (it != mapBlockIndex.end()) + BlockMap::iterator it = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(blockId); + if (it != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) pindex = it->second; } @@ -1684,7 +1694,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) if(params[2].get_bool()) filter = filter | ISMINE_WATCH_ONLY; - int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1; + int depth = pindex ? (1 + pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindex->nHeight) : -1; UniValue transactions(UniValue::VARR); @@ -1696,7 +1706,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) ListTransactions(tx, "*", 0, true, transactions, filter); } - CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms]; + CBlockIndex *pblockLast = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive[pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() + 1 - target_confirms]; uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256(); UniValue ret(UniValue::VOBJ); @@ -1923,6 +1933,13 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp) if (!pwalletMain->IsCrypted()) throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called."); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VNUM)(UniValue::VBOOL), true); + + // prevent trivial sendmoney commands when wallet left unlocked to stake + bool stakeOnly = false; + if (params.size() > 2) + stakeOnly = params[2].get_bool(); + // Note that the walletpassphrase is stored in params[0] which is not mlock()ed SecureString strWalletPass; strWalletPass.reserve(100); @@ -1947,16 +1964,12 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp) nWalletUnlockTime = GetTime() + nSleepTime; RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime); - // prevent trivial sendmoney commands when wallet left unlocked to stake - if (params.size() > 2) - fWalletUnlockStakingOnly = params[2].get_bool(); - else - fWalletUnlockStakingOnly = false; + + fWalletUnlockStakingOnly = stakeOnly; return NullUniValue; } - UniValue walletpassphrasechange(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index 47ad1d08..135dbb2e 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -5,7 +5,7 @@ #include "bitcoinconsensus.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include "pubkey.h" #include "script/interpreter.h" #include "version.h" @@ -43,7 +43,7 @@ class TxInputStream template TxInputStream& operator>>(T& obj) { - ::Unserialize(*this, obj, m_type, m_version); + ::Unserialize(*this, obj); return *this; } @@ -79,7 +79,7 @@ int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned i stream >> tx; if (nIn >= tx.vin.size()) return set_error(err, bitcoinconsensus_ERR_TX_INDEX); - if (tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) != txToLen) + if (GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) != txToLen) return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH); // Regardless of the verification result, the tx did not error. diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index f0f43f81..b05629e8 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -5,16 +5,17 @@ #include "interpreter.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include "crypto/ripemd160.h" #include "crypto/sha1.h" #include "crypto/sha256.h" #include "pubkey.h" #include "script/script.h" #include "uint256.h" -#include "util.h" +#include "util/util.h" #include "streams.h" #include "main.h" +#include "init.h" namespace { @@ -872,7 +873,7 @@ bool EvalScript(std::vector >& stack, const CScript& scriptCode.FindAndDelete(CScript(vchSig)); /// TODO: for backwards compatability, this should be implemented in a different way but for now it will do - if(chainActive.Tip()->nHeight > 1600000) + if(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nHeight > 1600000) { if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) { @@ -944,7 +945,7 @@ bool EvalScript(std::vector >& stack, const CScript& // distinguishable by CHECKMULTISIG NOT if the STRICTENC flag is set. // See the script_(in)valid tests for details. /// TODO: for backwards compatability, this should be implemented in a different way but for now it will do - if(chainActive.Tip()->nHeight > 1600000) + if(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nHeight > 1600000) { if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) { // serror is set @@ -1040,7 +1041,7 @@ class CTransactionSignatureSerializer { /** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */ template - void SerializeScriptCode(S &s, int nType, int nVersion) const { + void SerializeScriptCode(S &s) const { CScript::const_iterator it = scriptCode.begin(); CScript::const_iterator itBegin = it; opcodetype opcode; @@ -1063,53 +1064,55 @@ class CTransactionSignatureSerializer { /** Serialize an input of txTo */ template - void SerializeInput(S &s, unsigned int nInput, int nType, int nVersion) const { + void SerializeInput(S &s, unsigned int nInput) const { // In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized if (fAnyoneCanPay) nInput = nIn; // Serialize the prevout - ::Serialize(s, txTo.vin[nInput].prevout, nType, nVersion); + ::Serialize(s, txTo.vin[nInput].prevout); // Serialize the script if (nInput != nIn) // Blank out other inputs' signatures - ::Serialize(s, CScriptBase(), nType, nVersion); + ::Serialize(s, CScriptBase()); else - SerializeScriptCode(s, nType, nVersion); + SerializeScriptCode(s); // Serialize the nSequence if (nInput != nIn && (fHashSingle || fHashNone)) // let the others update at will - ::Serialize(s, (int)0, nType, nVersion); + ::Serialize(s, (int)0); else - ::Serialize(s, txTo.vin[nInput].nSequence, nType, nVersion); + ::Serialize(s, txTo.vin[nInput].nSequence); } /** Serialize an output of txTo */ template - void SerializeOutput(S &s, unsigned int nOutput, int nType, int nVersion) const { + void SerializeOutput(S &s, unsigned int nOutput) const { if (fHashSingle && nOutput != nIn) // Do not lock-in the txout payee at other indices as txin - ::Serialize(s, CTxOut(), nType, nVersion); + ::Serialize(s, CTxOut()); else - ::Serialize(s, txTo.vout[nOutput], nType, nVersion); + ::Serialize(s, txTo.vout[nOutput]); } /** Serialize txTo */ template - void Serialize(S &s, int nType, int nVersion) const { + void Serialize(S &s) const { // Serialize nVersion - ::Serialize(s, txTo.nVersion, nType, nVersion); + ::Serialize(s, txTo.nVersion); + // Serialize nTime + ::Serialize(s, txTo.nTime); // Serialize vin unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size(); ::WriteCompactSize(s, nInputs); for (unsigned int nInput = 0; nInput < nInputs; nInput++) - SerializeInput(s, nInput, nType, nVersion); + SerializeInput(s, nInput); // Serialize vout unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? nIn+1 : txTo.vout.size()); ::WriteCompactSize(s, nOutputs); for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++) - SerializeOutput(s, nOutput, nType, nVersion); + SerializeOutput(s, nOutput); // Serialize nLockTime - ::Serialize(s, txTo.nLockTime, nType, nVersion); + ::Serialize(s, txTo.nLockTime); } }; @@ -1117,65 +1120,25 @@ class CTransactionSignatureSerializer { uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) { - static const uint256 ret1(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); - if (nIn >= txTo.vin.size()) - { - LogPrintf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); - return ret1; - } - CTransaction txTmp(txTo); - - // In case concatenating two scripts ends up with two codeseparators, - // or an extra one at the end, this prevents all those possible incompatibilities. - scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR)); + assert(nIn < txTo.vin.size()); - // Blank out other inputs' signatures - for (unsigned int i = 0; i < txTmp.vin.size(); i++) - txTmp.vin[i].scriptSig = CScript(); - txTmp.vin[nIn].scriptSig = scriptCode; - - // Blank out some of the outputs - if ((nHashType & 0x1f) == SIGHASH_NONE) - { - // Wildcard payee - txTmp.vout.clear(); + static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); - // Let the others update at will - for (unsigned int i = 0; i < txTmp.vin.size(); i++) - if (i != nIn) - txTmp.vin[i].nSequence = 0; - } - else if ((nHashType & 0x1f) == SIGHASH_SINGLE) - { - // Only lock-in the txout payee at same index as txin - unsigned int nOut = nIn; - if (nOut >= txTmp.vout.size()) - { - LogPrintf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut); - return ret1; + // Check for invalid use of SIGHASH_SINGLE + if ((nHashType & 0x1f) == SIGHASH_SINGLE) { + if (nIn >= txTo.vout.size()) { + // nOut out of range + return one; } - txTmp.vout.resize(nOut+1); - for (unsigned int i = 0; i < nOut; i++) - txTmp.vout[i].SetNull(); - - // Let the others update at will - for (unsigned int i = 0; i < txTmp.vin.size(); i++) - if (i != nIn) - txTmp.vin[i].nSequence = 0; } - // Blank out other inputs completely, not recommended for open transactions - if (nHashType & SIGHASH_ANYONECANPAY) - { - txTmp.vin[0] = txTmp.vin[nIn]; - txTmp.vin.resize(1); - } + // Wrapper to serialize only the necessary parts of the transaction being signed + CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType); // Serialize and hash - CDataStream ss(SER_GETHASH, 0); - ss.reserve(10000); + CHashWriter ss(SER_GETHASH, 0); ss << txTmp << nHashType; - return Hash(ss.begin(), ss.end()); + return ss.GetHash(); } bool TransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 7082fe7e..2358857c 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -7,7 +7,7 @@ #define BITCOIN_SCRIPT_INTERPRETER_H #include "script_error.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include #include diff --git a/src/script/script.cpp b/src/script/script.cpp index 40f33fc9..2b82c6a0 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -7,7 +7,7 @@ #include "interpreter.h" #include "tinyformat.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" const char* GetOpName(opcodetype opcode) { diff --git a/src/script/script.h b/src/script/script.h index 6a83667d..237913ed 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -29,6 +29,12 @@ static const int MAX_OPS_PER_SCRIPT = 201; // Maximum number of public keys per multisig static const int MAX_PUBKEYS_PER_MULTISIG = 20; +// Maximum script length in bytes +static const int MAX_SCRIPT_SIZE = 10000; + +// Maximum number of values on script interpreter stack +static const int MAX_STACK_SIZE = 1000; + // Threshold for nLockTime: below this value it is interpreted as block number, // otherwise as UNIX timestamp. static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index b5bf7c54..0cef4cbc 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -9,7 +9,7 @@ #include "pubkey.h" #include "random.h" #include "uint256.h" -#include "util.h" +#include "util/util.h" #include "args.h" #include diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 7a7ba26b..623ff4e6 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -8,7 +8,7 @@ #include "key.h" #include "keystore.h" #include "policy/policy.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include "script/standard.h" #include "uint256.h" diff --git a/src/script/stakescript.cpp b/src/script/stakescript.cpp index 08f790b6..c16d039d 100644 --- a/src/script/stakescript.cpp +++ b/src/script/stakescript.cpp @@ -1,13 +1,13 @@ #include "stakescript.h" #include -#include "primitives/transaction.h" +#include "tx/tx.h" #include "interpreter.h" #include #include "sigcache.h" #include #include #include "sync.h" -#include "util.h" +#include "util/util.h" #include "args.h" #include "random.h" #include "key.h" diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 3fa551d2..ba783d19 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -7,8 +7,8 @@ #include "pubkey.h" #include "script/script.h" -#include "util.h" -#include "utilstrencodings.h" +#include "util/util.h" +#include "util/utilstrencodings.h" typedef std::vector valtype; diff --git a/src/serialize.h b/src/serialize.h index c8c60402..71af5201 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -9,227 +9,233 @@ #include "compat/crypto_endian.h" #include -#include +#include +#include +#include #include #include #include +#include #include -#include #include -#include #include #include #include "prevector.h" -static const unsigned int MAX_SIZE = 0x02000000; +static const uint64_t MAX_SIZE = 0x02000000; /** - * Used to bypass the rule against non-const reference to temporary - * where it makes sense with wrappers such as CFlatData or CTxDB + * Dummy data type to identify deserializing constructors. + * + * By convention, a constructor of a type T with signature + * + * template T::T(deserialize_type, Stream& s) + * + * is a deserializing constructor, which builds the type by deserializing it + * from s. If T contains const fields, this is likely the only way to do so. */ -template -inline T& REF(const T& val) -{ - return const_cast(val); -} +struct deserialize_type {}; +constexpr deserialize_type deserialize{}; /** - * Used to acquire a non-const pointer "this" to generate bodies - * of const serialization operations from a template + * Used to bypass the rule against non-const reference to temporary where it + * makes sense with wrappers such as CFlatData or CTxDB */ -template -inline T* NCONST_PTR(const T* val) -{ - return const_cast(val); +template inline T &REF(const T &val) { + return const_cast(val); } -/** - * Get begin pointer of vector (non-const version). - * @note These functions avoid the undefined case of indexing into an empty - * vector, as well as that of indexing after the end of the vector. +/** + * Used to acquire a non-const pointer "this" to generate bodies of const + * serialization operations from a template */ -template -inline typename V::value_type* begin_ptr(V& v) -{ - return v.empty() ? NULL : &v[0]; -} -/** Get begin pointer of vector (const version) */ -template -inline const typename V::value_type* begin_ptr(const V& v) -{ - return v.empty() ? NULL : &v[0]; -} -/** Get end pointer of vector (non-const version) */ -template -inline typename V::value_type* end_ptr(V& v) -{ - return v.empty() ? NULL : (&v[0] + v.size()); -} -/** Get end pointer of vector (const version) */ -template -inline const typename V::value_type* end_ptr(const V& v) -{ - return v.empty() ? NULL : (&v[0] + v.size()); +template inline T *NCONST_PTR(const T *val) { + return const_cast(val); } /* * Lowest-level serialization and conversion. * @note Sizes of these types are verified in the tests */ -template inline void ser_writedata8(Stream &s, uint8_t obj) -{ - s.write((char*)&obj, 1); +template inline void ser_writedata8(Stream &s, uint8_t obj) { + s.write((char *)&obj, 1); } -template inline void ser_writedata16(Stream &s, uint16_t obj) -{ +template +inline void ser_writedata16(Stream &s, uint16_t obj) { obj = htole16(obj); - s.write((char*)&obj, 2); + s.write((char *)&obj, 2); } -template inline void ser_writedata32(Stream &s, uint32_t obj) -{ +template +inline void ser_writedata32(Stream &s, uint32_t obj) { obj = htole32(obj); - s.write((char*)&obj, 4); + s.write((char *)&obj, 4); } -template inline void ser_writedata64(Stream &s, uint64_t obj) -{ +template +inline void ser_writedata64(Stream &s, uint64_t obj) { obj = htole64(obj); - s.write((char*)&obj, 8); + s.write((char *)&obj, 8); } -template inline uint8_t ser_readdata8(Stream &s) -{ +template inline uint8_t ser_readdata8(Stream &s) { uint8_t obj; - s.read((char*)&obj, 1); + s.read((char *)&obj, 1); return obj; } -template inline uint16_t ser_readdata16(Stream &s) -{ +template inline uint16_t ser_readdata16(Stream &s) { uint16_t obj; - s.read((char*)&obj, 2); + s.read((char *)&obj, 2); return le16toh(obj); } -template inline uint32_t ser_readdata32(Stream &s) -{ +template inline uint32_t ser_readdata32(Stream &s) { uint32_t obj; - s.read((char*)&obj, 4); + s.read((char *)&obj, 4); return le32toh(obj); } -template inline uint64_t ser_readdata64(Stream &s) -{ +template inline uint64_t ser_readdata64(Stream &s) { uint64_t obj; - s.read((char*)&obj, 8); + s.read((char *)&obj, 8); return le64toh(obj); } -inline uint64_t ser_double_to_uint64(double x) -{ - union { double x; uint64_t y; } tmp; +inline uint64_t ser_double_to_uint64(double x) { + union { + double x; + uint64_t y; + } tmp; tmp.x = x; return tmp.y; } -inline uint32_t ser_float_to_uint32(float x) -{ - union { float x; uint32_t y; } tmp; +inline uint32_t ser_float_to_uint32(float x) { + union { + float x; + uint32_t y; + } tmp; tmp.x = x; return tmp.y; } -inline double ser_uint64_to_double(uint64_t y) -{ - union { double x; uint64_t y; } tmp; +inline double ser_uint64_to_double(uint64_t y) { + union { + double x; + uint64_t y; + } tmp; tmp.y = y; return tmp.x; } -inline float ser_uint32_to_float(uint32_t y) -{ - union { float x; uint32_t y; } tmp; +inline float ser_uint32_to_float(uint32_t y) { + union { + float x; + uint32_t y; + } tmp; tmp.y = y; return tmp.x; } - ///////////////////////////////////////////////////////////////// // // Templates for serializing to anything that looks like a stream, // i.e. anything that supports .read(char*, size_t) and .write(char*, size_t) // +class CSizeComputer; -enum -{ +enum { // primary actions - SER_NETWORK = (1 << 0), - SER_DISK = (1 << 1), - SER_GETHASH = (1 << 2), + SER_NETWORK = (1 << 0), + SER_DISK = (1 << 1), + SER_GETHASH = (1 << 2), }; -#define READWRITE(obj) (::SerReadWrite(s, (obj), nType, nVersion, ser_action)) +#define READWRITE(obj) (::SerReadWrite(s, (obj), ser_action)) +#define READWRITEMANY(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__)) -/** - * Implement three methods for serializable objects. These are actually wrappers over - * "SerializationOp" template, which implements the body of each class' serialization - * code. Adding "ADD_SERIALIZE_METHODS" in the body of the class causes these wrappers to be - * added as members. +/** + * Implement three methods for serializable objects. These are actually wrappers + * over "SerializationOp" template, which implements the body of each class' + * serialization code. Adding "ADD_SERIALIZE_METHODS" in the body of the class + * causes these wrappers to be added as members. */ -#define ADD_SERIALIZE_METHODS \ - size_t GetSerializeSize(int nType, int nVersion) const { \ - CSizeComputer s(nType, nVersion); \ - NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion);\ - return s.size(); \ - } \ - template \ - void Serialize(Stream& s, int nType, int nVersion) const { \ - NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion);\ - } \ - template \ - void Unserialize(Stream& s, int nType, int nVersion) { \ - SerializationOp(s, CSerActionUnserialize(), nType, nVersion); \ +#define ADD_SERIALIZE_METHODS \ + template void Serialize(Stream &s) const { \ + NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize()); \ + } \ + template void Unserialize(Stream &s) { \ + SerializationOp(s, CSerActionUnserialize()); \ } -/* - * Basic Types - */ -inline unsigned int GetSerializeSize(char a, int, int=0) { return 1; } -inline unsigned int GetSerializeSize(int8_t a, int, int=0) { return 1; } -inline unsigned int GetSerializeSize(uint8_t a, int, int=0) { return 1; } -inline unsigned int GetSerializeSize(int16_t a, int, int=0) { return 2; } -inline unsigned int GetSerializeSize(uint16_t a, int, int=0) { return 2; } -inline unsigned int GetSerializeSize(int32_t a, int, int=0) { return 4; } -inline unsigned int GetSerializeSize(uint32_t a, int, int=0) { return 4; } -inline unsigned int GetSerializeSize(int64_t a, int, int=0) { return 8; } -inline unsigned int GetSerializeSize(uint64_t a, int, int=0) { return 8; } -inline unsigned int GetSerializeSize(float a, int, int=0) { return 4; } -inline unsigned int GetSerializeSize(double a, int, int=0) { return 8; } - -template inline void Serialize(Stream& s, char a, int, int=0) { ser_writedata8(s, a); } // TODO Get rid of bare char -template inline void Serialize(Stream& s, int8_t a, int, int=0) { ser_writedata8(s, a); } -template inline void Serialize(Stream& s, uint8_t a, int, int=0) { ser_writedata8(s, a); } -template inline void Serialize(Stream& s, int16_t a, int, int=0) { ser_writedata16(s, a); } -template inline void Serialize(Stream& s, uint16_t a, int, int=0) { ser_writedata16(s, a); } -template inline void Serialize(Stream& s, int32_t a, int, int=0) { ser_writedata32(s, a); } -template inline void Serialize(Stream& s, uint32_t a, int, int=0) { ser_writedata32(s, a); } -template inline void Serialize(Stream& s, int64_t a, int, int=0) { ser_writedata64(s, a); } -template inline void Serialize(Stream& s, uint64_t a, int, int=0) { ser_writedata64(s, a); } -template inline void Serialize(Stream& s, float a, int, int=0) { ser_writedata32(s, ser_float_to_uint32(a)); } -template inline void Serialize(Stream& s, double a, int, int=0) { ser_writedata64(s, ser_double_to_uint64(a)); } - -template inline void Unserialize(Stream& s, char& a, int, int=0) { a = ser_readdata8(s); } // TODO Get rid of bare char -template inline void Unserialize(Stream& s, int8_t& a, int, int=0) { a = ser_readdata8(s); } -template inline void Unserialize(Stream& s, uint8_t& a, int, int=0) { a = ser_readdata8(s); } -template inline void Unserialize(Stream& s, int16_t& a, int, int=0) { a = ser_readdata16(s); } -template inline void Unserialize(Stream& s, uint16_t& a, int, int=0) { a = ser_readdata16(s); } -template inline void Unserialize(Stream& s, int32_t& a, int, int=0) { a = ser_readdata32(s); } -template inline void Unserialize(Stream& s, uint32_t& a, int, int=0) { a = ser_readdata32(s); } -template inline void Unserialize(Stream& s, int64_t& a, int, int=0) { a = ser_readdata64(s); } -template inline void Unserialize(Stream& s, uint64_t& a, int, int=0) { a = ser_readdata64(s); } -template inline void Unserialize(Stream& s, float& a, int, int=0) { a = ser_uint32_to_float(ser_readdata32(s)); } -template inline void Unserialize(Stream& s, double& a, int, int=0) { a = ser_uint64_to_double(ser_readdata64(s)); } - -inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); } -template inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; ser_writedata8(s, f); } -template inline void Unserialize(Stream& s, bool& a, int, int=0) { char f=ser_readdata8(s); a=f; } - - - - +template inline void Serialize(Stream &s, char a) { + ser_writedata8(s, a); +} // TODO Get rid of bare char +template inline void Serialize(Stream &s, int8_t a) { + ser_writedata8(s, a); +} +template inline void Serialize(Stream &s, uint8_t a) { + ser_writedata8(s, a); +} +template inline void Serialize(Stream &s, int16_t a) { + ser_writedata16(s, a); +} +template inline void Serialize(Stream &s, uint16_t a) { + ser_writedata16(s, a); +} +template inline void Serialize(Stream &s, int32_t a) { + ser_writedata32(s, a); +} +template inline void Serialize(Stream &s, uint32_t a) { + ser_writedata32(s, a); +} +template inline void Serialize(Stream &s, int64_t a) { + ser_writedata64(s, a); +} +template inline void Serialize(Stream &s, uint64_t a) { + ser_writedata64(s, a); +} +template inline void Serialize(Stream &s, float a) { + ser_writedata32(s, ser_float_to_uint32(a)); +} +template inline void Serialize(Stream &s, double a) { + ser_writedata64(s, ser_double_to_uint64(a)); +} +// TODO Get rid of bare char +template inline void Unserialize(Stream &s, char &a) { + a = ser_readdata8(s); +} +template inline void Unserialize(Stream &s, int8_t &a) { + a = ser_readdata8(s); +} +template inline void Unserialize(Stream &s, uint8_t &a) { + a = ser_readdata8(s); +} +template inline void Unserialize(Stream &s, int16_t &a) { + a = ser_readdata16(s); +} +template inline void Unserialize(Stream &s, uint16_t &a) { + a = ser_readdata16(s); +} +template inline void Unserialize(Stream &s, int32_t &a) { + a = ser_readdata32(s); +} +template inline void Unserialize(Stream &s, uint32_t &a) { + a = ser_readdata32(s); +} +template inline void Unserialize(Stream &s, int64_t &a) { + a = ser_readdata64(s); +} +template inline void Unserialize(Stream &s, uint64_t &a) { + a = ser_readdata64(s); +} +template inline void Unserialize(Stream &s, float &a) { + a = ser_uint32_to_float(ser_readdata32(s)); +} +template inline void Unserialize(Stream &s, double &a) { + a = ser_uint64_to_double(ser_readdata64(s)); +} +template inline void Serialize(Stream &s, bool a) { + char f = a; + ser_writedata8(s, f); +} +template inline void Unserialize(Stream &s, bool &a) { + char f = ser_readdata8(s); + a = f; +} /** * Compact Size @@ -238,131 +244,112 @@ template inline void Unserialize(Stream& s, bool& a, int, int=0 * size <= UINT_MAX -- 5 bytes (254 + 4 bytes) * size > UINT_MAX -- 9 bytes (255 + 8 bytes) */ -inline unsigned int GetSizeOfCompactSize(uint64_t nSize) -{ - if (nSize < 253) return sizeof(unsigned char); - else if (nSize <= std::numeric_limits::max()) return sizeof(unsigned char) + sizeof(unsigned short); - else if (nSize <= std::numeric_limits::max()) return sizeof(unsigned char) + sizeof(unsigned int); - else return sizeof(unsigned char) + sizeof(uint64_t); +inline unsigned int GetSizeOfCompactSize(uint64_t nSize) { + if (nSize < 253) + return sizeof(uint8_t); + else if (nSize <= std::numeric_limits::max()) + return sizeof(uint8_t) + sizeof(unsigned short); + else if (nSize <= std::numeric_limits::max()) + return sizeof(uint8_t) + sizeof(unsigned int); + else + return sizeof(uint8_t) + sizeof(uint64_t); } -template -void WriteCompactSize(Stream& os, uint64_t nSize) -{ - if (nSize < 253) - { +inline void WriteCompactSize(CSizeComputer &os, uint64_t nSize); + +template void WriteCompactSize(Stream &os, uint64_t nSize) { + if (nSize < 253) { ser_writedata8(os, nSize); - } - else if (nSize <= std::numeric_limits::max()) - { + } else if (nSize <= std::numeric_limits::max()) { ser_writedata8(os, 253); ser_writedata16(os, nSize); - } - else if (nSize <= std::numeric_limits::max()) - { + } else if (nSize <= std::numeric_limits::max()) { ser_writedata8(os, 254); ser_writedata32(os, nSize); - } - else - { + } else { ser_writedata8(os, 255); ser_writedata64(os, nSize); } return; } -template -uint64_t ReadCompactSize(Stream& is) -{ +template uint64_t ReadCompactSize(Stream &is) { uint8_t chSize = ser_readdata8(is); uint64_t nSizeRet = 0; - if (chSize < 253) - { + if (chSize < 253) { nSizeRet = chSize; - } - else if (chSize == 253) - { + } else if (chSize == 253) { nSizeRet = ser_readdata16(is); if (nSizeRet < 253) throw std::ios_base::failure("non-canonical ReadCompactSize()"); - } - else if (chSize == 254) - { + } else if (chSize == 254) { nSizeRet = ser_readdata32(is); if (nSizeRet < 0x10000u) throw std::ios_base::failure("non-canonical ReadCompactSize()"); - } - else - { + } else { nSizeRet = ser_readdata64(is); if (nSizeRet < 0x100000000ULL) throw std::ios_base::failure("non-canonical ReadCompactSize()"); } - if (nSizeRet > (uint64_t)MAX_SIZE) + if (nSizeRet > MAX_SIZE) { throw std::ios_base::failure("ReadCompactSize(): size too large"); + } return nSizeRet; } /** * Variable-length integers: bytes are a MSB base-128 encoding of the number. * The high bit in each byte signifies whether another digit follows. To make - * sure the encoding is one-to-one, one is subtracted from all but the last digit. - * Thus, the byte sequence a[] with length len, where all but the last byte - * has bit 128 set, encodes the number: - * + * sure the encoding is one-to-one, one is subtracted from all but the last + * digit. Thus, the byte sequence a[] with length len, where all but the last + * byte has bit 128 set, encodes the number: + * * (a[len-1] & 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] & 0x7F)+1)) - * + * * Properties: * * Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes) * * Every integer has exactly one encoding * * Encoding does not depend on size of original integer type * * No redundancy: every (infinite) byte sequence corresponds to a list * of encoded integers. - * + * * 0: [0x00] 256: [0x81 0x00] * 1: [0x01] 16383: [0xFE 0x7F] * 127: [0x7F] 16384: [0xFF 0x00] - * 128: [0x80 0x00] 16511: [0x80 0xFF 0x7F] - * 255: [0x80 0x7F] 65535: [0x82 0xFD 0x7F] + * 128: [0x80 0x00] 16511: [0xFF 0x7F] + * 255: [0x80 0x7F] 65535: [0x82 0xFE 0x7F] * 2^32: [0x8E 0xFE 0xFE 0xFF 0x00] */ - -template -inline unsigned int GetSizeOfVarInt(I n) -{ +template inline unsigned int GetSizeOfVarInt(I n) { int nRet = 0; - while(true) { + while (true) { nRet++; - if (n <= 0x7F) - break; + if (n <= 0x7F) break; n = (n >> 7) - 1; } return nRet; } -template -void WriteVarInt(Stream& os, I n) -{ - unsigned char tmp[(sizeof(n)*8+6)/7]; - int len=0; - while(true) { +template inline void WriteVarInt(CSizeComputer &os, I n); + +template void WriteVarInt(Stream &os, I n) { + uint8_t tmp[(sizeof(n) * 8 + 6) / 7]; + int len = 0; + while (true) { tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00); - if (n <= 0x7F) - break; + if (n <= 0x7F) break; n = (n >> 7) - 1; len++; } do { ser_writedata8(os, tmp[len]); - } while(len--); + } while (len--); } -template -I ReadVarInt(Stream& is) -{ +template I ReadVarInt(Stream &is) { I n = 0; - while(true) { - unsigned char chData = ser_readdata8(is); + while (true) { + uint8_t chData = ser_readdata8(is); n = (n << 7) | (chData & 0x7F); if (chData & 0x80) n++; @@ -371,114 +358,103 @@ I ReadVarInt(Stream& is) } } -#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) +#define FLATDATA(obj) \ + REF(CFlatData((char *)&(obj), (char *)&(obj) + sizeof(obj))) #define VARINT(obj) REF(WrapVarInt(REF(obj))) -#define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj))) +#define COMPACTSIZE(obj) REF(CCompactSize(REF(obj))) +#define LIMITED_STRING(obj, n) REF(LimitedString(REF(obj))) -/** +/** * Wrapper for serializing arrays and POD. */ -class CFlatData -{ +class CFlatData { protected: - char* pbegin; - char* pend; + char *pbegin; + char *pend; + public: - CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { } - template - explicit CFlatData(std::vector &v) - { - pbegin = (char*)begin_ptr(v); - pend = (char*)end_ptr(v); + CFlatData(void *pbeginIn, void *pendIn) + : pbegin((char *)pbeginIn), pend((char *)pendIn) {} + template explicit CFlatData(std::vector &v) { + pbegin = (char *)v.data(); + pend = (char *)(v.data() + v.size()); } template - explicit CFlatData(prevector &v) - { - pbegin = (char*)begin_ptr(v); - pend = (char*)end_ptr(v); - } - char* begin() { return pbegin; } - const char* begin() const { return pbegin; } - char* end() { return pend; } - const char* end() const { return pend; } - - unsigned int GetSerializeSize(int, int=0) const - { - return pend - pbegin; + explicit CFlatData(prevector &v) { + pbegin = (char *)v.data(); + pend = (char *)(v.data() + v.size()); } + char *begin() { return pbegin; } + const char *begin() const { return pbegin; } + char *end() { return pend; } + const char *end() const { return pend; } - template - void Serialize(Stream& s, int, int=0) const - { + template void Serialize(Stream &s) const { s.write(pbegin, pend - pbegin); } - template - void Unserialize(Stream& s, int, int=0) - { + template void Unserialize(Stream &s) { s.read(pbegin, pend - pbegin); } }; -template -class CVarInt -{ +template class CVarInt { protected: I &n; + public: - CVarInt(I& nIn) : n(nIn) { } + CVarInt(I &nIn) : n(nIn) {} - unsigned int GetSerializeSize(int, int) const { - return GetSizeOfVarInt(n); + template void Serialize(Stream &s) const { + WriteVarInt(s, n); } - template - void Serialize(Stream &s, int, int) const { - WriteVarInt(s, n); + template void Unserialize(Stream &s) { + n = ReadVarInt(s); + } +}; + +class CCompactSize { +protected: + uint64_t &n; + +public: + CCompactSize(uint64_t &nIn) : n(nIn) {} + + template void Serialize(Stream &s) const { + WriteCompactSize(s, n); } - template - void Unserialize(Stream& s, int, int) { - n = ReadVarInt(s); + template void Unserialize(Stream &s) { + n = ReadCompactSize(s); } }; -template -class LimitedString -{ +template class LimitedString { protected: - std::string& string; + std::string &string; + public: - LimitedString(std::string& string) : string(string) {} + LimitedString(std::string &_string) : string(_string) {} - template - void Unserialize(Stream& s, int, int=0) - { + template void Unserialize(Stream &s) { size_t size = ReadCompactSize(s); if (size > Limit) { throw std::ios_base::failure("String length limit exceeded"); } string.resize(size); - if (size != 0) - s.read((char*)&string[0], size); + if (size != 0) s.read((char *)&string[0], size); } - template - void Serialize(Stream& s, int, int=0) const - { + template void Serialize(Stream &s) const { WriteCompactSize(s, string.size()); - if (!string.empty()) - s.write((char*)&string[0], string.size()); - } - - unsigned int GetSerializeSize(int, int=0) const - { - return GetSizeOfCompactSize(string.size()) + string.size(); + if (!string.empty()) s.write((char *)&string[0], string.size()); } }; -template -CVarInt WrapVarInt(I& n) { return CVarInt(n); } +template CVarInt WrapVarInt(I &n) { + return CVarInt(n); +} /** * Forward declarations @@ -487,455 +463,461 @@ CVarInt WrapVarInt(I& n) { return CVarInt(n); } /** * string */ -template unsigned int GetSerializeSize(const std::basic_string& str, int, int=0); -template void Serialize(Stream& os, const std::basic_string& str, int, int=0); -template void Unserialize(Stream& is, std::basic_string& str, int, int=0); +template +void Serialize(Stream &os, const std::basic_string &str); +template +void Unserialize(Stream &is, std::basic_string &str); /** * prevector - * prevectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. + * prevectors of uint8_t are a special case and are intended to be serialized as + * a single opaque blob. */ -template unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const unsigned char&); -template unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const V&); -template inline unsigned int GetSerializeSize(const prevector& v, int nType, int nVersion); -template void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const unsigned char&); -template void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const V&); -template inline void Serialize(Stream& os, const prevector& v, int nType, int nVersion); -template void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const unsigned char&); -template void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const V&); -template inline void Unserialize(Stream& is, prevector& v, int nType, int nVersion); +template +void Serialize_impl(Stream &os, const prevector &v, const uint8_t &); +template +void Serialize_impl(Stream &os, const prevector &v, const V &); +template +inline void Serialize(Stream &os, const prevector &v); +template +void Unserialize_impl(Stream &is, prevector &v, const uint8_t &); +template +void Unserialize_impl(Stream &is, prevector &v, const V &); +template +inline void Unserialize(Stream &is, prevector &v); /** * vector - * vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. + * vectors of uint8_t are a special case and are intended to be serialized as a + * single opaque blob. */ -template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const unsigned char&); -template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const V&); -template inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion); -template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const unsigned char&); -template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const V&); -template inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion); -template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const unsigned char&); -template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const V&); -template inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion); +template +void Serialize_impl(Stream &os, const std::vector &v, const uint8_t &); +template +void Serialize_impl(Stream &os, const std::vector &v, const V &); +template +inline void Serialize(Stream &os, const std::vector &v); +template +void Unserialize_impl(Stream &is, std::vector &v, const uint8_t &); +template +void Unserialize_impl(Stream &is, std::vector &v, const V &); +template +inline void Unserialize(Stream &is, std::vector &v); /** * pair */ -template unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion); -template void Serialize(Stream& os, const std::pair& item, int nType, int nVersion); -template void Unserialize(Stream& is, std::pair& item, int nType, int nVersion); +template +void Serialize(Stream &os, const std::pair &item); +template +void Unserialize(Stream &is, std::pair &item); /** * map */ -template unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion); -template void Serialize(Stream& os, const std::map& m, int nType, int nVersion); -template void Unserialize(Stream& is, std::map& m, int nType, int nVersion); +template +void Serialize(Stream &os, const std::map &m); +template +void Unserialize(Stream &is, std::map &m); /** * set */ -template unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion); -template void Serialize(Stream& os, const std::set& m, int nType, int nVersion); -template void Unserialize(Stream& is, std::set& m, int nType, int nVersion); - - - +template +void Serialize(Stream &os, const std::set &m); +template +void Unserialize(Stream &is, std::set &m); +/** + * shared_ptr + */ +template +void Serialize(Stream &os, const std::shared_ptr &p); +template +void Unserialize(Stream &os, std::shared_ptr &p); /** - * If none of the specialized versions above matched, default to calling member function. - * "int nType" is changed to "long nType" to keep from getting an ambiguous overload error. - * The compiler will only cast int to long if none of the other templates matched. - * Thanks to Boost serialization for this idea. + * unique_ptr */ -template -inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion) -{ - return a.GetSerializeSize((int)nType, nVersion); -} +template +void Serialize(Stream &os, const std::unique_ptr &p); +template +void Unserialize(Stream &os, std::unique_ptr &p); -template -inline void Serialize(Stream& os, const T& a, long nType, int nVersion) -{ - a.Serialize(os, (int)nType, nVersion); +/** + * If none of the specialized versions above matched, default to calling member + * function. + */ +template +inline void Serialize(Stream &os, const T &a) { + a.Serialize(os); } -template -inline void Unserialize(Stream& is, T& a, long nType, int nVersion) -{ - a.Unserialize(is, (int)nType, nVersion); +template +inline void Unserialize(Stream &is, T &a) { + a.Unserialize(is); } - - - - /** * string */ -template -unsigned int GetSerializeSize(const std::basic_string& str, int, int) -{ - return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); -} - -template -void Serialize(Stream& os, const std::basic_string& str, int, int) -{ +template +void Serialize(Stream &os, const std::basic_string &str) { WriteCompactSize(os, str.size()); - if (!str.empty()) - os.write((char*)&str[0], str.size() * sizeof(str[0])); + if (!str.empty()) os.write((char *)&str[0], str.size() * sizeof(str[0])); } -template -void Unserialize(Stream& is, std::basic_string& str, int, int) -{ +template +void Unserialize(Stream &is, std::basic_string &str) { unsigned int nSize = ReadCompactSize(is); str.resize(nSize); - if (nSize != 0) - is.read((char*)&str[0], nSize * sizeof(str[0])); + if (nSize != 0) is.read((char *)&str[0], nSize * sizeof(str[0])); } - - /** * prevector */ -template -unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const unsigned char&) -{ - return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); -} - -template -unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const V&) -{ - unsigned int nSize = GetSizeOfCompactSize(v.size()); - for (typename prevector::const_iterator vi = v.begin(); vi != v.end(); ++vi) - nSize += GetSerializeSize((*vi), nType, nVersion); - return nSize; -} - -template -inline unsigned int GetSerializeSize(const prevector& v, int nType, int nVersion) -{ - return GetSerializeSize_impl(v, nType, nVersion, T()); -} - - -template -void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const unsigned char&) -{ +template +void Serialize_impl(Stream &os, const prevector &v, const uint8_t &) { WriteCompactSize(os, v.size()); - if (!v.empty()) - os.write((char*)&v[0], v.size() * sizeof(T)); + if (!v.empty()) os.write((char *)&v[0], v.size() * sizeof(T)); } -template -void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const V&) -{ +template +void Serialize_impl(Stream &os, const prevector &v, const V &) { WriteCompactSize(os, v.size()); - for (typename prevector::const_iterator vi = v.begin(); vi != v.end(); ++vi) - ::Serialize(os, (*vi), nType, nVersion); + for (typename prevector::const_iterator vi = v.begin(); vi != v.end(); + ++vi) + ::Serialize(os, (*vi)); } -template -inline void Serialize(Stream& os, const prevector& v, int nType, int nVersion) -{ - Serialize_impl(os, v, nType, nVersion, T()); +template +inline void Serialize(Stream &os, const prevector &v) { + Serialize_impl(os, v, T()); } - -template -void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const unsigned char&) -{ +template +void Unserialize_impl(Stream &is, prevector &v, const uint8_t &) { // Limit size per read so bogus size value won't cause out of memory v.clear(); unsigned int nSize = ReadCompactSize(is); unsigned int i = 0; - while (i < nSize) - { - unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); + while (i < nSize) { + unsigned int blk = + std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); v.resize(i + blk); - is.read((char*)&v[i], blk * sizeof(T)); + is.read((char *)&v[i], blk * sizeof(T)); i += blk; } } -template -void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const V&) -{ +template +void Unserialize_impl(Stream &is, prevector &v, const V &) { v.clear(); unsigned int nSize = ReadCompactSize(is); unsigned int i = 0; unsigned int nMid = 0; - while (nMid < nSize) - { + while (nMid < nSize) { nMid += 5000000 / sizeof(T); - if (nMid > nSize) - nMid = nSize; + if (nMid > nSize) nMid = nSize; v.resize(nMid); for (; i < nMid; i++) - Unserialize(is, v[i], nType, nVersion); + Unserialize(is, v[i]); } } -template -inline void Unserialize(Stream& is, prevector& v, int nType, int nVersion) -{ - Unserialize_impl(is, v, nType, nVersion, T()); +template +inline void Unserialize(Stream &is, prevector &v) { + Unserialize_impl(is, v, T()); } - - /** * vector */ -template -unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const unsigned char&) -{ - return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); -} - -template -unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const V&) -{ - unsigned int nSize = GetSizeOfCompactSize(v.size()); - for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) - nSize += GetSerializeSize((*vi), nType, nVersion); - return nSize; -} - -template -inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion) -{ - return GetSerializeSize_impl(v, nType, nVersion, T()); -} - - -template -void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const unsigned char&) -{ +template +void Serialize_impl(Stream &os, const std::vector &v, const uint8_t &) { WriteCompactSize(os, v.size()); - if (!v.empty()) - os.write((char*)&v[0], v.size() * sizeof(T)); + if (!v.empty()) os.write((char *)&v[0], v.size() * sizeof(T)); } -template -void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const V&) -{ +template +void Serialize_impl(Stream &os, const std::vector &v, const V &) { WriteCompactSize(os, v.size()); - for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) - ::Serialize(os, (*vi), nType, nVersion); + for (typename std::vector::const_iterator vi = v.begin(); + vi != v.end(); ++vi) + ::Serialize(os, (*vi)); } -template -inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion) -{ - Serialize_impl(os, v, nType, nVersion, T()); +template +inline void Serialize(Stream &os, const std::vector &v) { + Serialize_impl(os, v, T()); } - -template -void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const unsigned char&) -{ +template +void Unserialize_impl(Stream &is, std::vector &v, const uint8_t &) { // Limit size per read so bogus size value won't cause out of memory v.clear(); unsigned int nSize = ReadCompactSize(is); unsigned int i = 0; - while (i < nSize) - { - unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); + while (i < nSize) { + unsigned int blk = + std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); v.resize(i + blk); - is.read((char*)&v[i], blk * sizeof(T)); + is.read((char *)&v[i], blk * sizeof(T)); i += blk; } } -template -void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const V&) -{ +template +void Unserialize_impl(Stream &is, std::vector &v, const V &) { v.clear(); unsigned int nSize = ReadCompactSize(is); unsigned int i = 0; unsigned int nMid = 0; - while (nMid < nSize) - { + while (nMid < nSize) { nMid += 5000000 / sizeof(T); - if (nMid > nSize) - nMid = nSize; + if (nMid > nSize) nMid = nSize; v.resize(nMid); for (; i < nMid; i++) - Unserialize(is, v[i], nType, nVersion); + Unserialize(is, v[i]); } } -template -inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion) -{ - Unserialize_impl(is, v, nType, nVersion, T()); +template +inline void Unserialize(Stream &is, std::vector &v) { + Unserialize_impl(is, v, T()); } - - /** * pair */ -template -unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion) -{ - return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion); +template +void Serialize(Stream &os, const std::pair &item) { + Serialize(os, item.first); + Serialize(os, item.second); } -template -void Serialize(Stream& os, const std::pair& item, int nType, int nVersion) -{ - Serialize(os, item.first, nType, nVersion); - Serialize(os, item.second, nType, nVersion); +template +void Unserialize(Stream &is, std::pair &item) { + Unserialize(is, item.first); + Unserialize(is, item.second); } -template -void Unserialize(Stream& is, std::pair& item, int nType, int nVersion) -{ - Unserialize(is, item.first, nType, nVersion); - Unserialize(is, item.second, nType, nVersion); -} - - - /** * map */ -template -unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion) -{ - unsigned int nSize = GetSizeOfCompactSize(m.size()); - for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) - nSize += GetSerializeSize((*mi), nType, nVersion); - return nSize; -} - -template -void Serialize(Stream& os, const std::map& m, int nType, int nVersion) -{ +template +void Serialize(Stream &os, const std::map &m) { WriteCompactSize(os, m.size()); - for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) - Serialize(os, (*mi), nType, nVersion); + for (typename std::map::const_iterator mi = m.begin(); + mi != m.end(); ++mi) + Serialize(os, (*mi)); } -template -void Unserialize(Stream& is, std::map& m, int nType, int nVersion) -{ +template +void Unserialize(Stream &is, std::map &m) { m.clear(); unsigned int nSize = ReadCompactSize(is); typename std::map::iterator mi = m.begin(); - for (unsigned int i = 0; i < nSize; i++) - { + for (unsigned int i = 0; i < nSize; i++) { std::pair item; - Unserialize(is, item, nType, nVersion); + Unserialize(is, item); mi = m.insert(mi, item); } } - - /** * set */ -template -unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion) -{ - unsigned int nSize = GetSizeOfCompactSize(m.size()); - for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) - nSize += GetSerializeSize((*it), nType, nVersion); - return nSize; -} - -template -void Serialize(Stream& os, const std::set& m, int nType, int nVersion) -{ +template +void Serialize(Stream &os, const std::set &m) { WriteCompactSize(os, m.size()); - for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) - Serialize(os, (*it), nType, nVersion); + for (typename std::set::const_iterator it = m.begin(); + it != m.end(); ++it) + Serialize(os, (*it)); } -template -void Unserialize(Stream& is, std::set& m, int nType, int nVersion) -{ +template +void Unserialize(Stream &is, std::set &m) { m.clear(); unsigned int nSize = ReadCompactSize(is); typename std::set::iterator it = m.begin(); - for (unsigned int i = 0; i < nSize; i++) - { + for (unsigned int i = 0; i < nSize; i++) { K key; - Unserialize(is, key, nType, nVersion); + Unserialize(is, key); it = m.insert(it, key); } } +/** + * unique_ptr + */ +template +void Serialize(Stream &os, const std::unique_ptr &p) { + Serialize(os, *p); +} +template +void Unserialize(Stream &is, std::unique_ptr &p) { + p.reset(new T(deserialize, is)); +} + +/** + * shared_ptr + */ +template +void Serialize(Stream &os, const std::shared_ptr &p) { + Serialize(os, *p); +} + +template +void Unserialize(Stream &is, std::shared_ptr &p) { + p = std::make_shared(deserialize, is); +} /** * Support for ADD_SERIALIZE_METHODS and READWRITE macro */ -struct CSerActionSerialize -{ - bool ForRead() const { return false; } +struct CSerActionSerialize { + constexpr bool ForRead() const { return false; } }; -struct CSerActionUnserialize -{ - bool ForRead() const { return true; } +struct CSerActionUnserialize { + constexpr bool ForRead() const { return true; } }; -template -inline void SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action) -{ - ::Serialize(s, obj, nType, nVersion); +template +inline void SerReadWrite(Stream &s, const T &obj, + CSerActionSerialize ser_action) { + ::Serialize(s, obj); } -template -inline void SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action) -{ - ::Unserialize(s, obj, nType, nVersion); +template +inline void SerReadWrite(Stream &s, T &obj, CSerActionUnserialize ser_action) { + ::Unserialize(s, obj); } +/** + * ::GetSerializeSize implementations + * + * Computing the serialized size of objects is done through a special stream + * object of type CSizeComputer, which only records the number of bytes written + * to it. + * + * If your Serialize or SerializationOp method has non-trivial overhead for + * serialization, it may be worthwhile to implement a specialized version for + * CSizeComputer, which uses the s.seek() method to record bytes that would + * be written instead. + */ +class CSizeComputer { +protected: + size_t nSize; + const int nType; + const int nVersion; +public: + CSizeComputer(int nTypeIn, int nVersionIn) + : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {} + void write(const char *psz, size_t _nSize) { this->nSize += _nSize; } + /** Pretend _nSize bytes are written, without specifying them. */ + void seek(size_t _nSize) { this->nSize += _nSize; } + template CSizeComputer &operator<<(const T &obj) { + ::Serialize(*this, obj); + return (*this); + } + size_t size() const { return nSize; } + int GetVersion() const { return nVersion; } + int GetType() const { return nType; } +}; -class CSizeComputer -{ -protected: - size_t nSize; +template void SerializeMany(Stream &s) {} -public: - int nType; - int nVersion; +template +void SerializeMany(Stream &s, Arg &&arg) { + ::Serialize(s, std::forward(arg)); +} - CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {} +template +void SerializeMany(Stream &s, Arg &&arg, Args &&... args) { + ::Serialize(s, std::forward(arg)); + ::SerializeMany(s, std::forward(args)...); +} - CSizeComputer& write(const char *psz, size_t nSize) - { - this->nSize += nSize; - return *this; - } +template inline void UnserializeMany(Stream &s) {} - template - CSizeComputer& operator<<(const T& obj) - { - ::Serialize(*this, obj, nType, nVersion); - return (*this); - } +template +inline void UnserializeMany(Stream &s, Arg &arg) { + ::Unserialize(s, arg); +} - size_t size() const { - return nSize; - } -}; +template +inline void UnserializeMany(Stream &s, Arg &arg, Args &... args) { + ::Unserialize(s, arg); + ::UnserializeMany(s, args...); +} + +template +inline void SerReadWriteMany(Stream &s, CSerActionSerialize ser_action, + Args &&... args) { + ::SerializeMany(s, std::forward(args)...); +} + +template +inline void SerReadWriteMany(Stream &s, CSerActionUnserialize ser_action, + Args &... args) { + ::UnserializeMany(s, args...); +} + +template inline void WriteVarInt(CSizeComputer &s, I n) { + s.seek(GetSizeOfVarInt(n)); +} + +inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize) { + s.seek(GetSizeOfCompactSize(nSize)); +} + +template +size_t GetSerializeSize(const T &t, int nType, int nVersion = 0) { + return (CSizeComputer(nType, nVersion) << t).size(); +} + +template +size_t GetSerializeSize(const S &s, const T &t) { + return (CSizeComputer(s.GetType(), s.GetVersion()) << t).size(); +} + +/** + * Get begin pointer of vector (non-const version). + * @note These functions avoid the undefined case of indexing into an empty + * vector, as well as that of indexing after the end of the vector. + */ +template +inline typename V::value_type* begin_ptr(V& v) +{ + return v.empty() ? NULL : &v[0]; +} +/** Get begin pointer of vector (const version) */ +template +inline const typename V::value_type* begin_ptr(const V& v) +{ + return v.empty() ? NULL : &v[0]; +} +/** Get end pointer of vector (non-const version) */ +template +inline typename V::value_type* end_ptr(V& v) +{ + return v.empty() ? NULL : (&v[0] + v.size()); +} +/** Get end pointer of vector (const version) */ +template +inline const typename V::value_type* end_ptr(const V& v) +{ + return v.empty() ? NULL : (&v[0] + v.size()); +} #endif // BITCOIN_SERIALIZE_H diff --git a/src/signals.cpp b/src/signals.cpp new file mode 100644 index 00000000..20904ab7 --- /dev/null +++ b/src/signals.cpp @@ -0,0 +1,21 @@ +#include "signals.h" +#include "messages.h" +#include "main.h" + +void RegisterNodeSignals(CNodeSignals& nodeSignals) +{ + nodeSignals.GetHeight.connect(&GetHeight); + nodeSignals.ProcessMessages.connect(&ProcessMessages); + nodeSignals.SendMessages.connect(&SendMessages); + nodeSignals.InitializeNode.connect(&InitializeNode); + nodeSignals.FinalizeNode.connect(&FinalizeNode); +} + +void UnregisterNodeSignals(CNodeSignals& nodeSignals) +{ + nodeSignals.GetHeight.disconnect(&GetHeight); + nodeSignals.ProcessMessages.disconnect(&ProcessMessages); + nodeSignals.SendMessages.disconnect(&SendMessages); + nodeSignals.InitializeNode.disconnect(&InitializeNode); + nodeSignals.FinalizeNode.disconnect(&FinalizeNode); +} diff --git a/src/signals.h b/src/signals.h new file mode 100644 index 00000000..7ee824c1 --- /dev/null +++ b/src/signals.h @@ -0,0 +1,12 @@ +#ifndef SIGNALS_H +#define SIGNALS_H + +#include "net.h" + +/** Register with a network node to receive its signals */ +void RegisterNodeSignals(CNodeSignals& nodeSignals); +/** Unregister a network node */ +void UnregisterNodeSignals(CNodeSignals& nodeSignals); + + +#endif // SIGNALS_H diff --git a/src/streams.h b/src/streams.h index 0fc6135a..cb45c47b 100644 --- a/src/streams.h +++ b/src/streams.h @@ -22,278 +22,364 @@ #include #include -/** Double ended buffer combining vector and stream-like interfaces. +template class OverrideStream { + Stream *stream; + + const int nType; + const int nVersion; + +public: + OverrideStream(Stream *stream_, int nType_, int nVersion_) + : stream(stream_), nType(nType_), nVersion(nVersion_) {} + + template OverrideStream &operator<<(const T &obj) { + // Serialize to this stream + ::Serialize(*this, obj); + return (*this); + } + + template OverrideStream &operator>>(T &obj) { + // Unserialize from this stream + ::Unserialize(*this, obj); + return (*this); + } + + void write(const char *pch, size_t nSize) { stream->write(pch, nSize); } + + void read(char *pch, size_t nSize) { stream->read(pch, nSize); } + + int GetVersion() const { return nVersion; } + int GetType() const { return nType; } +}; + +template OverrideStream WithOrVersion(S *s, int nVersionFlag) { + return OverrideStream(s, s->GetType(), s->GetVersion() | nVersionFlag); +} + +/** + * Minimal stream for overwriting and/or appending to an existing byte vector. + * + * The referenced vector will grow as necessary. + */ +class CVectorWriter { +public: + /** + * @param[in] nTypeIn Serialization Type + * @param[in] nVersionIn Serialization Version (including any flags) + * @param[in] vchDataIn Referenced byte vector to overwrite/append + * @param[in] nPosIn Starting position. Vector index where writes should + * start. The vector will initially grow as necessary to max(index, + * vec.size()). So to append, use vec.size(). + */ + CVectorWriter(int nTypeIn, int nVersionIn, std::vector &vchDataIn, + size_t nPosIn) + : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), + nPos(nPosIn) { + if (nPos > vchData.size()) vchData.resize(nPos); + } + /** + * (other params same as above) + * @param[in] args A list of items to serialize starting at nPos. + */ + template + CVectorWriter(int nTypeIn, int nVersionIn, std::vector &vchDataIn, + size_t nPosIn, Args &&... args) + : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn) { + ::SerializeMany(*this, std::forward(args)...); + } + void write(const char *pch, size_t nSize) { + assert(nPos <= vchData.size()); + size_t nOverwrite = std::min(nSize, vchData.size() - nPos); + if (nOverwrite) { + memcpy(vchData.data() + nPos, + reinterpret_cast(pch), nOverwrite); + } + if (nOverwrite < nSize) { + vchData.insert(vchData.end(), + reinterpret_cast(pch) + nOverwrite, + reinterpret_cast(pch) + nSize); + } + nPos += nSize; + } + template CVectorWriter &operator<<(const T &obj) { + // Serialize to this stream + ::Serialize(*this, obj); + return (*this); + } + int GetVersion() const { return nVersion; } + int GetType() const { return nType; } + void seek(size_t nSize) { + nPos += nSize; + if (nPos > vchData.size()) vchData.resize(nPos); + } + +private: + const int nType; + const int nVersion; + std::vector &vchData; + size_t nPos; +}; + +/** + * Double ended buffer combining vector and stream-like interfaces. * - * >> and << read and write unformatted data using the above serialization templates. - * Fills with data in linear time; some stringstream implementations take N^2 time. + * >> and << read and write unformatted data using the above serialization + * templates. Fills with data in linear time; some stringstream implementations + * take N^2 time. */ -class CDataStream -{ +class CDataStream { protected: typedef CSerializeData vector_type; vector_type vch; unsigned int nReadPos; -public: + int nType; int nVersion; - typedef vector_type::allocator_type allocator_type; - typedef vector_type::size_type size_type; - typedef vector_type::difference_type difference_type; - typedef vector_type::reference reference; - typedef vector_type::const_reference const_reference; - typedef vector_type::value_type value_type; - typedef vector_type::iterator iterator; - typedef vector_type::const_iterator const_iterator; +public: + typedef vector_type::allocator_type allocator_type; + typedef vector_type::size_type size_type; + typedef vector_type::difference_type difference_type; + typedef vector_type::reference reference; + typedef vector_type::const_reference const_reference; + typedef vector_type::value_type value_type; + typedef vector_type::iterator iterator; + typedef vector_type::const_iterator const_iterator; typedef vector_type::reverse_iterator reverse_iterator; - explicit CDataStream(int nTypeIn, int nVersionIn) - { + explicit CDataStream(int nTypeIn, int nVersionIn) { + Init(nTypeIn, nVersionIn); + } + + CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, + int nVersionIn) + : vch(pbegin, pend) { Init(nTypeIn, nVersionIn); } - CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend) - { + CDataStream(const char *pbegin, const char *pend, int nTypeIn, + int nVersionIn) + : vch(pbegin, pend) { Init(nTypeIn, nVersionIn); } -#if !defined(_MSC_VER) || _MSC_VER >= 1300 - CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend) - { + CDataStream(const vector_type &vchIn, int nTypeIn, int nVersionIn) + : vch(vchIn.begin(), vchIn.end()) { Init(nTypeIn, nVersionIn); } -#endif - CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) - { + CDataStream(const std::vector &vchIn, int nTypeIn, int nVersionIn) + : vch(vchIn.begin(), vchIn.end()) { Init(nTypeIn, nVersionIn); } - CDataStream(const std::vector& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) - { + CDataStream(const std::vector &vchIn, int nTypeIn, int nVersionIn) + : vch(vchIn.begin(), vchIn.end()) { Init(nTypeIn, nVersionIn); } - CDataStream(const std::vector& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) - { + template + CDataStream(int nTypeIn, int nVersionIn, Args &&... args) { Init(nTypeIn, nVersionIn); + ::SerializeMany(*this, std::forward(args)...); } - void Init(int nTypeIn, int nVersionIn) - { + void Init(int nTypeIn, int nVersionIn) { nReadPos = 0; nType = nTypeIn; nVersion = nVersionIn; } - CDataStream& operator+=(const CDataStream& b) - { + CDataStream &operator+=(const CDataStream &b) { vch.insert(vch.end(), b.begin(), b.end()); return *this; } - friend CDataStream operator+(const CDataStream& a, const CDataStream& b) - { + friend CDataStream operator+(const CDataStream &a, const CDataStream &b) { CDataStream ret = a; ret += b; return (ret); } - std::string str() const - { - return (std::string(begin(), end())); - } - + std::string str() const { return (std::string(begin(), end())); } // // Vector subset // - const_iterator begin() const { return vch.begin() + nReadPos; } - iterator begin() { return vch.begin() + nReadPos; } - const_iterator end() const { return vch.end(); } - iterator end() { return vch.end(); } - size_type size() const { return vch.size() - nReadPos; } - bool empty() const { return vch.size() == nReadPos; } - void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); } - void reserve(size_type n) { vch.reserve(n + nReadPos); } - const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; } - reference operator[](size_type pos) { return vch[pos + nReadPos]; } - void clear() { vch.clear(); nReadPos = 0; } - iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); } - void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); } - - void insert(iterator it, std::vector::const_iterator first, std::vector::const_iterator last) - { - assert(last - first >= 0); - if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) - { + const_iterator begin() const { return vch.begin() + nReadPos; } + iterator begin() { return vch.begin() + nReadPos; } + const_iterator end() const { return vch.end(); } + iterator end() { return vch.end(); } + size_type size() const { return vch.size() - nReadPos; } + bool empty() const { return vch.size() == nReadPos; } + void resize(size_type n, value_type c = 0) { vch.resize(n + nReadPos, c); } + void reserve(size_type n) { vch.reserve(n + nReadPos); } + const_reference operator[](size_type pos) const { + return vch[pos + nReadPos]; + } + reference operator[](size_type pos) { return vch[pos + nReadPos]; } + void clear() { + vch.clear(); + nReadPos = 0; + } + iterator insert(iterator it, const char &x = char()) { + return vch.insert(it, x); + } + void insert(iterator it, size_type n, const char &x) { + vch.insert(it, n, x); + } + value_type *data() { return vch.data() + nReadPos; } + const value_type *data() const { return vch.data() + nReadPos; } + + void insert(iterator it, std::vector::const_iterator first, + std::vector::const_iterator last) { + if (last == first) { + return; + } + + assert(last - first > 0); + if (it == vch.begin() + nReadPos && + (unsigned int)(last - first) <= nReadPos) { // special case for inserting at the front when there's room nReadPos -= (last - first); memcpy(&vch[nReadPos], &first[0], last - first); - } - else + } else { vch.insert(it, first, last); + } } -#if !defined(_MSC_VER) || _MSC_VER >= 1300 - void insert(iterator it, const char* first, const char* last) - { - assert(last - first >= 0); - if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) - { + void insert(iterator it, const char *first, const char *last) { + if (last == first) { + return; + } + + assert(last - first > 0); + if (it == vch.begin() + nReadPos && + (unsigned int)(last - first) <= nReadPos) { // special case for inserting at the front when there's room nReadPos -= (last - first); memcpy(&vch[nReadPos], &first[0], last - first); - } - else + } else { vch.insert(it, first, last); + } } -#endif - iterator erase(iterator it) - { - if (it == vch.begin() + nReadPos) - { + iterator erase(iterator it) { + if (it == vch.begin() + nReadPos) { // special case for erasing from the front - if (++nReadPos >= vch.size()) - { - // whenever we reach the end, we take the opportunity to clear the buffer + if (++nReadPos >= vch.size()) { + // whenever we reach the end, we take the opportunity to clear + // the buffer nReadPos = 0; return vch.erase(vch.begin(), vch.end()); } return vch.begin() + nReadPos; - } - else + } else { return vch.erase(it); + } } - iterator erase(iterator first, iterator last) - { - if (first == vch.begin() + nReadPos) - { + iterator erase(iterator first, iterator last) { + if (first == vch.begin() + nReadPos) { // special case for erasing from the front - if (last == vch.end()) - { + if (last == vch.end()) { nReadPos = 0; return vch.erase(vch.begin(), vch.end()); - } - else - { + } else { nReadPos = (last - vch.begin()); return last; } - } - else + } else return vch.erase(first, last); } - inline void Compact() - { + inline void Compact() { vch.erase(vch.begin(), vch.begin() + nReadPos); nReadPos = 0; } - bool Rewind(size_type n) - { + bool Rewind(size_type n) { // Rewind by n characters if the buffer hasn't been compacted yet - if (n > nReadPos) - return false; + if (n > nReadPos) return false; nReadPos -= n; return true; } - // // Stream subset // - bool eof() const { return size() == 0; } - CDataStream* rdbuf() { return this; } - int in_avail() { return size(); } - - void SetType(int n) { nType = n; } - int GetType() { return nType; } - void SetVersion(int n) { nVersion = n; } - int GetVersion() { return nVersion; } - void ReadVersion() { *this >> nVersion; } - void WriteVersion() { *this << nVersion; } - - CDataStream& read(char* pch, size_t nSize) - { + bool eof() const { return size() == 0; } + CDataStream *rdbuf() { return this; } + int in_avail() { return size(); } + + void SetType(int n) { nType = n; } + int GetType() const { return nType; } + void SetVersion(int n) { nVersion = n; } + int GetVersion() const { return nVersion; } + + void read(char *pch, size_t nSize) { + if (nSize == 0) { + return; + } + // Read from the beginning of the buffer unsigned int nReadPosNext = nReadPos + nSize; - if (nReadPosNext >= vch.size()) - { - if (nReadPosNext > vch.size()) - { - throw std::ios_base::failure("CDataStream::read(): end of data"); + if (nReadPosNext >= vch.size()) { + if (nReadPosNext > vch.size()) { + throw std::ios_base::failure( + "CDataStream::read(): end of data"); } memcpy(pch, &vch[nReadPos], nSize); nReadPos = 0; vch.clear(); - return (*this); + return; } memcpy(pch, &vch[nReadPos], nSize); nReadPos = nReadPosNext; - return (*this); } - CDataStream& ignore(int nSize) - { + void ignore(int nSize) { // Ignore from the beginning of the buffer - assert(nSize >= 0); + if (nSize < 0) { + throw std::ios_base::failure( + "CDataStream::ignore(): nSize negative"); + } unsigned int nReadPosNext = nReadPos + nSize; - if (nReadPosNext >= vch.size()) - { + if (nReadPosNext >= vch.size()) { if (nReadPosNext > vch.size()) - throw std::ios_base::failure("CDataStream::ignore(): end of data"); + throw std::ios_base::failure( + "CDataStream::ignore(): end of data"); nReadPos = 0; vch.clear(); - return (*this); + return; } nReadPos = nReadPosNext; - return (*this); } - CDataStream& write(const char* pch, size_t nSize) - { + void write(const char *pch, size_t nSize) { // Write to the end of the buffer vch.insert(vch.end(), pch, pch + nSize); - return (*this); } - template - void Serialize(Stream& s, int nType, int nVersion) const - { + template void Serialize(Stream &s) const { // Special case: stream << stream concatenates like stream += stream - if (!vch.empty()) - s.write((char*)&vch[0], vch.size() * sizeof(vch[0])); + if (!vch.empty()) s.write((char *)&vch[0], vch.size() * sizeof(vch[0])); } - template - unsigned int GetSerializeSize(const T& obj) - { - // Tells the size of the object if serialized to this stream - return ::GetSerializeSize(obj, nType, nVersion); - } - - template - CDataStream& operator<<(const T& obj) - { + template CDataStream &operator<<(const T &obj) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } - template - CDataStream& operator>>(T& obj) - { + template CDataStream &operator>>(T &obj) { // Unserialize from this stream - ::Unserialize(*this, obj, nType, nVersion); + ::Unserialize(*this, obj); return (*this); } - void GetAndClear(CSerializeData &data) { - data.insert(data.end(), begin(), end()); + void GetAndClear(CSerializeData &d) { + d.insert(d.end(), begin(), end()); clear(); } @@ -302,8 +388,7 @@ class CDataStream * * @param[in] key The key used to XOR the data in this stream. */ - void Xor(const std::vector& key) - { + void Xor(const std::vector &key) { if (key.size() == 0) { return; } @@ -312,157 +397,156 @@ class CDataStream vch[i] ^= key[j++]; // This potentially acts on very many bytes of data, so it's - // important that we calculate `j`, i.e. the `key` index in this - // way instead of doing a %, which would effectively be a division - // for each byte Xor'd -- much slower than need be. - if (j == key.size()) - j = 0; + // important that we calculate `j`, i.e. the `key` index in this way + // instead of doing a %, which would effectively be a division for + // each byte Xor'd -- much slower than need be. + if (j == key.size()) j = 0; } } }; - - - - - - - - - -/** Non-refcounted RAII wrapper for FILE* +/** + * Non-refcounted RAII wrapper for FILE* * - * Will automatically close the file when it goes out of scope if not null. - * If you're returning the file pointer, return file.release(). - * If you need to close the file early, use file.fclose() instead of fclose(file). + * Will automatically close the file when it goes out of scope if not null. If + * you're returning the file pointer, return file.release(). If you need to + * close the file early, use file.fclose() instead of fclose(file). */ -class CAutoFile -{ +class CAutoFile { private: // Disallow copies - CAutoFile(const CAutoFile&); - CAutoFile& operator=(const CAutoFile&); + CAutoFile(const CAutoFile &); + CAutoFile &operator=(const CAutoFile &); - int nType; - int nVersion; - - FILE* file; + const int nType; + const int nVersion; + + FILE *file; public: - CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) - { + CAutoFile(FILE *filenew, int nTypeIn, int nVersionIn) + : nType(nTypeIn), nVersion(nVersionIn) { file = filenew; - nType = nTypeIn; - nVersion = nVersionIn; } - ~CAutoFile() - { - fclose(); - } + ~CAutoFile() { fclose(); } - void fclose() - { + void fclose() { if (file) { ::fclose(file); - file = NULL; + file = nullptr; } } - /** Get wrapped FILE* with transfer of ownership. - * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller - * of this function to clean up the returned FILE*. + /** + * Get wrapped FILE* with transfer of ownership. + * @note This will invalidate the CAutoFile object, and makes it the + * responsibility of the caller of this function to clean up the returned + * FILE*. */ - FILE* release() { FILE* ret = file; file = NULL; return ret; } + FILE *release() { + FILE *ret = file; + file = nullptr; + return ret; + } - /** Get wrapped FILE* without transfer of ownership. - * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the - * CAutoFile outlives use of the passed pointer. + /** + * Get wrapped FILE* without transfer of ownership. + * @note Ownership of the FILE* will remain with this class. Use this only + * if the scope of the CAutoFile outlives use of the passed pointer. */ - FILE* Get() const { return file; } + FILE *Get() const { return file; } - /** Return true if the wrapped FILE* is NULL, false otherwise. - */ - bool IsNull() const { return (file == NULL); } + /** Return true if the wrapped FILE* is nullptr, false otherwise. */ + bool IsNull() const { return (file == nullptr); } // // Stream subset // - void SetType(int n) { nType = n; } - int GetType() { return nType; } - void SetVersion(int n) { nVersion = n; } - int GetVersion() { return nVersion; } - void ReadVersion() { *this >> nVersion; } - void WriteVersion() { *this << nVersion; } - - CAutoFile& read(char* pch, size_t nSize) - { + int GetType() const { return nType; } + int GetVersion() const { return nVersion; } + + void read(char *pch, size_t nSize) { if (!file) - throw std::ios_base::failure("CAutoFile::read: file handle is NULL"); + throw std::ios_base::failure( + "CAutoFile::read: file handle is nullptr"); if (fread(pch, 1, nSize, file) != nSize) - throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed"); - return (*this); + throw std::ios_base::failure(feof(file) + ? "CAutoFile::read: end of file" + : "CAutoFile::read: fread failed"); } - CAutoFile& write(const char* pch, size_t nSize) - { + void ignore(size_t nSize) { if (!file) - throw std::ios_base::failure("CAutoFile::write: file handle is NULL"); - if (fwrite(pch, 1, nSize, file) != nSize) - throw std::ios_base::failure("CAutoFile::write: write failed"); - return (*this); + throw std::ios_base::failure( + "CAutoFile::ignore: file handle is nullptr"); + uint8_t data[4096]; + while (nSize > 0) { + size_t nNow = std::min(nSize, sizeof(data)); + if (fread(data, 1, nNow, file) != nNow) + throw std::ios_base::failure( + feof(file) ? "CAutoFile::ignore: end of file" + : "CAutoFile::read: fread failed"); + nSize -= nNow; + } } - template - unsigned int GetSerializeSize(const T& obj) - { - // Tells the size of the object if serialized to this stream - return ::GetSerializeSize(obj, nType, nVersion); + void write(const char *pch, size_t nSize) { + if (!file) + throw std::ios_base::failure( + "CAutoFile::write: file handle is nullptr"); + if (fwrite(pch, 1, nSize, file) != nSize) + throw std::ios_base::failure("CAutoFile::write: write failed"); } - template - CAutoFile& operator<<(const T& obj) - { + template CAutoFile &operator<<(const T &obj) { // Serialize to this stream if (!file) - throw std::ios_base::failure("CAutoFile::operator<<: file handle is NULL"); - ::Serialize(*this, obj, nType, nVersion); + throw std::ios_base::failure( + "CAutoFile::operator<<: file handle is nullptr"); + ::Serialize(*this, obj); return (*this); } - template - CAutoFile& operator>>(T& obj) - { + template CAutoFile &operator>>(T &obj) { // Unserialize from this stream if (!file) - throw std::ios_base::failure("CAutoFile::operator>>: file handle is NULL"); - ::Unserialize(*this, obj, nType, nVersion); + throw std::ios_base::failure( + "CAutoFile::operator>>: file handle is nullptr"); + ::Unserialize(*this, obj); return (*this); } }; -/** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to - * deserialize from. It guarantees the ability to rewind a given number of bytes. +/** + * Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to + * deserialize from. It guarantees the ability to rewind a given number of + * bytes. * - * Will automatically close the file when it goes out of scope if not null. - * If you need to close the file early, use file.fclose() instead of fclose(file). + * Will automatically close the file when it goes out of scope if not null. If + * you need to close the file early, use file.fclose() instead of fclose(file). */ -class CBufferedFile -{ +class CBufferedFile { private: // Disallow copies - CBufferedFile(const CBufferedFile&); - CBufferedFile& operator=(const CBufferedFile&); - - int nType; - int nVersion; - - FILE *src; // source file - uint64_t nSrcPos; // how many bytes have been read from source - uint64_t nReadPos; // how many bytes have been read from this - uint64_t nReadLimit; // up to which position we're allowed to read - uint64_t nRewind; // how many bytes we guarantee to rewind - std::vector vchBuf; // the buffer + CBufferedFile(const CBufferedFile &); + CBufferedFile &operator=(const CBufferedFile &); + + const int nType; + const int nVersion; + + // source file + FILE *src; + // how many bytes have been read from source + uint64_t nSrcPos; + // how many bytes have been read from this + uint64_t nReadPos; + // up to which position we're allowed to read + uint64_t nReadLimit; + // how many bytes we guarantee to rewind + uint64_t nRewind; + // the buffer + std::vector vchBuf; protected: // read data from the source to fill the buffer @@ -470,13 +554,13 @@ class CBufferedFile unsigned int pos = nSrcPos % vchBuf.size(); unsigned int readNow = vchBuf.size() - pos; unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind; - if (nAvail < readNow) - readNow = nAvail; - if (readNow == 0) - return false; - size_t read = fread((void*)&vchBuf[pos], 1, readNow, src); + if (nAvail < readNow) readNow = nAvail; + if (readNow == 0) return false; + size_t read = fread((void *)&vchBuf[pos], 1, readNow, src); if (read == 0) { - throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed"); + throw std::ios_base::failure( + feof(src) ? "CBufferedFile::Fill: end of file" + : "CBufferedFile::Fill: fread failed"); } else { nSrcPos += read; return true; @@ -484,59 +568,49 @@ class CBufferedFile } public: - CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) : - nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0) - { + CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, + int nTypeIn, int nVersionIn) + : nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), + nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0) { src = fileIn; - nType = nTypeIn; - nVersion = nVersionIn; } - ~CBufferedFile() - { - fclose(); - } + ~CBufferedFile() { fclose(); } - void fclose() - { + int GetVersion() const { return nVersion; } + int GetType() const { return nType; } + + void fclose() { if (src) { ::fclose(src); - src = NULL; + src = nullptr; } } // check whether we're at the end of the source file - bool eof() const { - return nReadPos == nSrcPos && feof(src); - } + bool eof() const { return nReadPos == nSrcPos && feof(src); } // read a number of bytes - CBufferedFile& read(char *pch, size_t nSize) { + void read(char *pch, size_t nSize) { if (nSize + nReadPos > nReadLimit) throw std::ios_base::failure("Read attempted past buffer limit"); if (nSize + nRewind > vchBuf.size()) throw std::ios_base::failure("Read larger than buffer size"); while (nSize > 0) { - if (nReadPos == nSrcPos) - Fill(); + if (nReadPos == nSrcPos) Fill(); unsigned int pos = nReadPos % vchBuf.size(); size_t nNow = nSize; - if (nNow + pos > vchBuf.size()) - nNow = vchBuf.size() - pos; - if (nNow + nReadPos > nSrcPos) - nNow = nSrcPos - nReadPos; + if (nNow + pos > vchBuf.size()) nNow = vchBuf.size() - pos; + if (nNow + nReadPos > nSrcPos) nNow = nSrcPos - nReadPos; memcpy(pch, &vchBuf[pos], nNow); nReadPos += nNow; pch += nNow; nSize -= nNow; } - return (*this); } // return the current reading position - uint64_t GetPos() { - return nReadPos; - } + uint64_t GetPos() { return nReadPos; } // rewind to a given reading position bool SetPos(uint64_t nPos) { @@ -554,39 +628,32 @@ class CBufferedFile bool Seek(uint64_t nPos) { long nLongPos = nPos; - if (nPos != (uint64_t)nLongPos) - return false; - if (fseek(src, nLongPos, SEEK_SET)) - return false; + if (nPos != (uint64_t)nLongPos) return false; + if (fseek(src, nLongPos, SEEK_SET)) return false; nLongPos = ftell(src); nSrcPos = nLongPos; nReadPos = nLongPos; return true; } - // prevent reading beyond a certain position - // no argument removes the limit + // Prevent reading beyond a certain position. No argument removes the limit. bool SetLimit(uint64_t nPos = (uint64_t)(-1)) { - if (nPos < nReadPos) - return false; + if (nPos < nReadPos) return false; nReadLimit = nPos; return true; } - template - CBufferedFile& operator>>(T& obj) { + template CBufferedFile &operator>>(T &obj) { // Unserialize from this stream - ::Unserialize(*this, obj, nType, nVersion); + ::Unserialize(*this, obj); return (*this); } // search for a given byte in the stream, and remain positioned on it void FindByte(char ch) { while (true) { - if (nReadPos == nSrcPos) - Fill(); - if (vchBuf[nReadPos % vchBuf.size()] == ch) - break; + if (nReadPos == nSrcPos) Fill(); + if (vchBuf[nReadPos % vchBuf.size()] == ch) break; nReadPos++; } } diff --git a/src/support/pagelocker.cpp b/src/support/pagelocker.cpp index 7cea2d88..29040be9 100644 --- a/src/support/pagelocker.cpp +++ b/src/support/pagelocker.cpp @@ -4,10 +4,6 @@ #include "support/pagelocker.h" -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #ifdef WIN32 #ifdef _WIN32_WINNT #undef _WIN32_WINNT @@ -17,6 +13,7 @@ #ifndef NOMINMAX #define NOMINMAX #endif +#include #include // This is used to attempt to keep keying material out of swap // Note that VirtualLock does not provide this as a guarantee on Windows, diff --git a/src/sync.cpp b/src/sync.cpp index 05c2fd40..07ba5377 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -4,8 +4,8 @@ #include "sync.h" -#include "util.h" -#include "utilstrencodings.h" +#include "util/util.h" +#include "util/utilstrencodings.h" #include diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp index 95491e66..34d0c6d4 100644 --- a/src/test/Checkpoints_tests.cpp +++ b/src/test/Checkpoints_tests.cpp @@ -1,33 +1,28 @@ +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + // // Unit tests for block-chain checkpoints // -#include // for 'map_list_of()' -#include -#include "../checkpoints.h" -#include "../util.h" +#include "checkpoints.h" + +#include "chainparams.h" +#include "test/test_bitcoin.h" +#include "uint256.h" + +#include using namespace std; -BOOST_AUTO_TEST_SUITE(Checkpoints_tests) +BOOST_FIXTURE_TEST_SUITE(Checkpoints_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sanity) { - uint256 p11111 = uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"); - uint256 p134444 = uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"); - BOOST_CHECK(Checkpoints::CheckBlock(14542, p11111)); - BOOST_CHECK(Checkpoints::CheckBlock(134444, p134444)); - - - // Wrong hashes at checkpoints should fail: - BOOST_CHECK(!Checkpoints::CheckBlock(14542, p134444)); - BOOST_CHECK(!Checkpoints::CheckBlock(134444, p11111)); - - // ... but any hash not at a checkpoint should succeed: - BOOST_CHECK(Checkpoints::CheckBlock(14542+1, p134444)); - BOOST_CHECK(Checkpoints::CheckBlock(134444+1, p11111)); - - BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 134444); -} + const CCheckpointData &checkpoints = Params(CBaseChainParams::MAIN).Checkpoints(); + BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate(checkpoints) >= 134444); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index fda11916..821966f2 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -1,146 +1,312 @@ -// -// Unit tests for denial-of-service detection/prevention code -// -#include +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include // for 'map_list_of()' -#include -#include +// Unit tests for denial-of-service detection/prevention code +#include "chainparams.h" +#include "dosman.h" +#include "keystore.h" #include "main.h" -#include "wallet.h" #include "net.h" +#include "pow.h" +#include "script/sign.h" +#include "serialize.h" #include "util.h" +#include "test/test_bitcoin.h" + #include +#include // for 'map_list_of()' +#include +#include +#include +#include + // Tests this internal-to-main.cpp method: -extern bool AddOrphanTx(const CDataStream& vMsg); -extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); -extern std::map mapOrphanTransactions; -extern std::map > mapOrphanTransactionsByPrev; +extern bool AddOrphanTx(const CTransaction &tx, NodeId peer); +extern void EraseOrphansFor(NodeId peer); +extern void EraseOrphansByTime(); +extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans, uint64_t nMaxBytes); CService ip(uint32_t i) { struct in_addr s; s.s_addr = i; - return CService(CNetAddr(s), GetDefaultPort()); + return CService(CNetAddr(s), Params().GetDefaultPort()); } -BOOST_AUTO_TEST_SUITE(DoS_tests) +BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup) -BOOST_AUTO_TEST_CASE(DoS_banning) +size_t GetNumberBanEntries() { - CNode::ClearBanned(); + banmap_t banmap; + dosMan.GetBanned(banmap); + return banmap.size(); +} + +bool DoesBanlistFileExist() { return boost::filesystem::exists(boost::filesystem::path(GetDataDir() / "banlist.dat")); } +bool RemoveBanlistFile() +{ + boost::filesystem::path path(GetDataDir() / "banlist.dat"); + try + { + if (boost::filesystem::exists(path)) + { + // if the file already exists, remove it + boost::filesystem::remove(path); + } + + // if we get here, we either successfully deleted the file, or it didn't exist + return true; + } + catch (const std::exception &e) + { + // there was an error deleting the file + return false; + } +} + +void SetKnownBanlistContents() +{ + // empty out any current entries + dosMan.ClearBanned(); + + // Add test ban of specific IP + dosMan.Ban(CNetAddr("192.168.1.1"), BanReasonNodeMisbehaving, DEFAULT_MISBEHAVING_BANTIME, false); + + // Add test ban of specific subnet + dosMan.Ban(CSubNet("10.168.1.0/28"), BanReasonManuallyAdded, DEFAULT_MISBEHAVING_BANTIME, false); +} + +BOOST_AUTO_TEST_CASE(DoS_persistence_tests) +{ + // 1. Test handling when banlist cannot be loaded from disk (reason doesn't matter) + // Ensure we don't have a banlist on the file system currently + BOOST_CHECK(RemoveBanlistFile()); + + // Initialize banlist to have 2 specific known entries + SetKnownBanlistContents(); + + // The current implementation does not touch the in-memory banlist if load from disk fails + dosMan.LoadBanlist(); + // Verify that since we couldn't load from disk, the in-memory values weren't overridden + BOOST_CHECK(GetNumberBanEntries() == 2); + // Also ensure we didn't write a file to disk + BOOST_CHECK(!DoesBanlistFileExist()); + + // 2. Test handling when banlist can be loaded from disk + dosMan.ClearBanned(); + // write an empty banlist file to disk + dosMan.DumpBanlist(); + // Initialize banlist to have 2 specific known entries + SetKnownBanlistContents(); + // Ensure that before load, we have 2 ban entries in the banlist + BOOST_CHECK(GetNumberBanEntries() == 2); + // Read from file, this should succeed and overwrite the in-memory banlist + // NOTE: LoadBanlist calls SweepBanned, which will clear out any expired ban entries so ensure + // that the test ban entries expire far enough in the future that it doesn't break this test + dosMan.LoadBanlist(); + // Ensure that we overwrote the in-memory banlist and now have no entries + BOOST_CHECK(GetNumberBanEntries() == 0); + + // 3. Test handling when reading from disk a second time without writing out changes + // Initialize banlist to have 2 specific known entries + SetKnownBanlistContents(); + // Ensure that before load, we have 2 ban entries in the banlist + BOOST_CHECK(GetNumberBanEntries() == 2); + // Read from file, this should succeed and overwrite the in-memory banlist + dosMan.LoadBanlist(); + // Ensure that we overwrote the in-memory banlist and now have no entries + BOOST_CHECK(GetNumberBanEntries() == 0); + + // 4. Test writing out to file then reading back in + // Initialize banlist to have 2 specific known entries + SetKnownBanlistContents(); + // Ensure that before load, we have 2 ban entries in the banlist + BOOST_CHECK(GetNumberBanEntries() == 2); + // Now write out to file + dosMan.DumpBanlist(); + // Verify the contents in-memory haven't changed + // NOTE: GetBanned calls SweepBanned, this will clear out any expired ban entries so ensure + // that the test ban entries expire far enough in the future that it doesn't break this test + BOOST_CHECK(GetNumberBanEntries() == 2); + // Clear in-memory banlist, then load from file and ensure we the 2 entries back + dosMan.ClearBanned(); + BOOST_CHECK(GetNumberBanEntries() == 0); + dosMan.LoadBanlist(); + BOOST_CHECK(GetNumberBanEntries() == 2); + + // Clean up in-memory banlist + dosMan.ClearBanned(); + // Clean up on-disk banlist + RemoveBanlistFile(); +} + +BOOST_AUTO_TEST_CASE(DoS_basic_ban_tests) +{ + // Ensure in-memory banlist is empty + dosMan.ClearBanned(); + BOOST_CHECK(GetNumberBanEntries() == 0); + + // Add a CNetAddr entry to banlist + dosMan.Ban(CNetAddr("192.168.1.1"), BanReasonNodeMisbehaving, DEFAULT_MISBEHAVING_BANTIME, false); + // Ensure we have exactly 1 entry in our banlist + BOOST_CHECK(GetNumberBanEntries() == 1); + // Add a CSubNet entry to banlist + dosMan.Ban(CSubNet("10.168.1.0/28"), BanReasonManuallyAdded, DEFAULT_MISBEHAVING_BANTIME, false); + // Ensure we have exactly 2 entries in our banlist + BOOST_CHECK(GetNumberBanEntries() == 2); + + // Verify IsBanned works for single IP directly specified + BOOST_CHECK(dosMan.IsBanned(CNetAddr("192.168.1.1"))); + // Verify IsBanned works for single IP not banned + BOOST_CHECK(!dosMan.IsBanned(CNetAddr("192.168.1.2"))); + // Verify IsBanned works for single IP banned as part of subnet + BOOST_CHECK(dosMan.IsBanned(CNetAddr("10.168.1.1"))); + // Verify IsBanned works for single IP not banned as part of subnet + BOOST_CHECK(!dosMan.IsBanned(CNetAddr("10.168.1.19"))); + // Verify IsBanned works for subnet exact match + BOOST_CHECK(dosMan.IsBanned(CSubNet("10.168.1.0/28"))); + // Verify IsBanned works for subnet not banned + BOOST_CHECK(!dosMan.IsBanned(CSubNet("10.168.1.64/30"))); + + // REVISIT: Currently subnets require EXACT matches, so the encompassed case should return not banned. + BOOST_CHECK(!dosMan.IsBanned(CSubNet("10.168.1.4/30"))); + + // Verify unbanning an IP not banned doesn't change banlist contents + dosMan.Unban(CNetAddr("192.168.10.1")); + // Ensure we still have exactly 2 entries in our banlist + BOOST_CHECK(GetNumberBanEntries() == 2); + + // Verify unbanning an IP that is within a subnet, but not directly banned, doesn't + // change our banlist conents + dosMan.Unban(CNetAddr("10.168.1.1")); + // Ensure we still have exactly 2 entries in our banlist + BOOST_CHECK(GetNumberBanEntries() == 2); + // Verify that the IP we just "unbanned" still shows as banned since it still falls within banned subnet + BOOST_CHECK(dosMan.IsBanned(CNetAddr("10.168.1.1"))); + + // Verify that unbanning an IP that is banned works + dosMan.Unban(CNetAddr("192.168.1.1")); + // Ensure we now have exactly 1 entry in our banlist + BOOST_CHECK(GetNumberBanEntries() == 1); + + // Verify that unbanning a subnet that is inside a banned subnet doesn't change our banlist contents + dosMan.Unban(CSubNet("10.168.1.4/30")); + // Ensure we still have exactly 1 entry in our banlist + BOOST_CHECK(GetNumberBanEntries() == 1); + + // Verify that unbanning a subnet that encompasses a banned subnet doesn't change our banlist conents + dosMan.Unban(CSubNet("10.168.1.0/24")); + // Ensure we still have exactly 1 entry in our banlist + BOOST_CHECK(GetNumberBanEntries() == 1); + + // Verify that unbanning a subnet that exactly matches a banned subnet updates our banlist conents + dosMan.Unban(CSubNet("10.168.1.0/28")); + // Ensure we now have exactly 0 entries in our banlist + BOOST_CHECK(GetNumberBanEntries() == 0); + + // Re-add ban entries so we can test ClearBanned() + SetKnownBanlistContents(); + // Ensure we have exactly 2 entries in our banlist + BOOST_CHECK(GetNumberBanEntries() == 2); + + // Clear the in-memory banlist + dosMan.ClearBanned(); + // Ensure in-memory banlist is now empty + BOOST_CHECK(GetNumberBanEntries() == 0); +} + +BOOST_AUTO_TEST_CASE(DoS_misbehaving_ban_tests) +{ + dosMan.ClearBanned(); CAddress addr1(ip(0xa0b0c001)); CNode dummyNode1(INVALID_SOCKET, addr1, "", true); - dummyNode1.Misbehaving(100); // Should get banned - BOOST_CHECK(CNode::IsBanned(addr1)); - BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned + dummyNode1.nVersion = 1; + dosMan.Misbehaving(&dummyNode1, 100); // Should get banned + SendMessages(&dummyNode1); + BOOST_CHECK(dosMan.IsBanned(addr1)); + BOOST_CHECK(!dosMan.IsBanned(ip(0xa0b0c001 | 0x0000ff00))); // Different IP, not banned CAddress addr2(ip(0xa0b0c002)); CNode dummyNode2(INVALID_SOCKET, addr2, "", true); - dummyNode2.Misbehaving(50); - BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet... - BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be - dummyNode2.Misbehaving(50); - BOOST_CHECK(CNode::IsBanned(addr2)); -} - -BOOST_AUTO_TEST_CASE(DoS_banscore) + dummyNode2.nVersion = 1; + dosMan.Misbehaving(&dummyNode2, 50); + SendMessages(&dummyNode2); + BOOST_CHECK(!dosMan.IsBanned(addr2)); // 2 not banned yet... + BOOST_CHECK(dosMan.IsBanned(addr1)); // ... but 1 still should be + dosMan.Misbehaving(&dummyNode2, 50); + SendMessages(&dummyNode2); + BOOST_CHECK(dosMan.IsBanned(addr2)); +} + +BOOST_AUTO_TEST_CASE(DoS_non_default_banscore) { - CNode::ClearBanned(); + dosMan.ClearBanned(); mapArgs["-banscore"] = "111"; // because 11 is my favorite number CAddress addr1(ip(0xa0b0c001)); CNode dummyNode1(INVALID_SOCKET, addr1, "", true); - dummyNode1.Misbehaving(100); - BOOST_CHECK(!CNode::IsBanned(addr1)); - dummyNode1.Misbehaving(10); - BOOST_CHECK(!CNode::IsBanned(addr1)); - dummyNode1.Misbehaving(1); - BOOST_CHECK(CNode::IsBanned(addr1)); + dosMan.HandleCommandLine(); + dummyNode1.nVersion = 1; + dosMan.Misbehaving(&dummyNode1, 100); + SendMessages(&dummyNode1); + BOOST_CHECK(!dosMan.IsBanned(addr1)); + dosMan.Misbehaving(&dummyNode1, 10); + SendMessages(&dummyNode1); + BOOST_CHECK(!dosMan.IsBanned(addr1)); + dosMan.Misbehaving(&dummyNode1, 1); + SendMessages(&dummyNode1); + BOOST_CHECK(dosMan.IsBanned(addr1)); mapArgs.erase("-banscore"); + dosMan.HandleCommandLine(); } -BOOST_AUTO_TEST_CASE(DoS_bantime) +BOOST_AUTO_TEST_CASE(DoS_bantime_expiration) { - CNode::ClearBanned(); - int64 nStartTime = GetTime(); + dosMan.ClearBanned(); + int64_t nStartTime = GetTime(); SetMockTime(nStartTime); // Overrides future calls to GetTime() CAddress addr(ip(0xa0b0c001)); CNode dummyNode(INVALID_SOCKET, addr, "", true); + dummyNode.nVersion = 1; - dummyNode.Misbehaving(100); - BOOST_CHECK(CNode::IsBanned(addr)); + dosMan.Misbehaving(&dummyNode, 100); + SendMessages(&dummyNode); + BOOST_CHECK(dosMan.IsBanned(addr)); - SetMockTime(nStartTime+60*60); - BOOST_CHECK(CNode::IsBanned(addr)); + // Verify that SweepBanned does not remove the entry + dosMan.SweepBanned(); + // Ensure we still have exactly 1 entry in our banlist + BOOST_CHECK(GetNumberBanEntries() == 1); - SetMockTime(nStartTime+60*60*24+1); - BOOST_CHECK(!CNode::IsBanned(addr)); -} + SetMockTime(nStartTime + 60 * 60); + BOOST_CHECK(dosMan.IsBanned(addr)); -static bool CheckNBits(unsigned int nbits1, int64 time1, unsigned int nbits2, int64 time2)\ -{ - if (time1 > time2) - return CheckNBits(nbits2, time2, nbits1, time1); - int64 deltaTime = time2-time1; - - CBigNum required; - required.SetCompact(ComputeMinWork(nbits1, deltaTime)); - CBigNum have; - have.SetCompact(nbits2); - return (have <= required); -} + // Verify that SweepBanned still does not remove the entry + dosMan.SweepBanned(); + // Ensure we still have exactly 1 entry in our banlist + BOOST_CHECK(GetNumberBanEntries() == 1); -BOOST_AUTO_TEST_CASE(DoS_checknbits) -{ - using namespace boost::assign; // for 'map_list_of()' - - // Timestamps,nBits from the bitcoin blockchain. - // These are the block-chain checkpoint blocks - typedef std::map BlockData; - BlockData chainData = - map_list_of(1239852051,486604799)(1262749024,486594666) - (1279305360,469854461)(1280200847,469830746)(1281678674,469809688) - (1296207707,453179945)(1302624061,453036989)(1309640330,437004818) - (1313172719,436789733); - - // Make sure CheckNBits considers every combination of block-chain-lock-in-points - // "sane": - for (auto const& i: chainData) - { - for (auto const& j: chainData) - { - BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first)); - } - } + SetMockTime(nStartTime + 60 * 60 * 24 + 1); + BOOST_CHECK(!dosMan.IsBanned(addr)); - // Test a couple of insane combinations: - BlockData::value_type firstcheck = *(chainData.begin()); - BlockData::value_type lastcheck = *(chainData.rbegin()); - - // First checkpoint difficulty at or a while after the last checkpoint time should fail when - // compared to last checkpoint - BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*10, lastcheck.second, lastcheck.first)); - BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*60*24*14, lastcheck.second, lastcheck.first)); - - // ... but OK if enough time passed for difficulty to adjust downward: - BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first)); - + // Verify that SweepBanned does remove the entry this time as it is expired + dosMan.SweepBanned(); + // Ensure we now have exactly 0 entries in our banlist + BOOST_CHECK(GetNumberBanEntries() == 0); } CTransaction RandomOrphan() { - std::map::iterator it; + std::map::iterator it; it = mapOrphanTransactions.lower_bound(GetRandHash()); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); - const CDataStream* pvMsg = it->second; - CTransaction tx; - CDataStream(*pvMsg) >> tx; - return tx; + return it->second.tx; } BOOST_AUTO_TEST_CASE(DoS_mapOrphans) @@ -150,21 +316,49 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) CBasicKeyStore keystore; keystore.AddKey(key); + // Test LimitOrphanTxSize() function: limit by orphan pool bytes + // add 50 orphan transactions: + for (int i = 0; i < 50; i++) + { + CMutableTransaction tx; + tx.vin.resize(1); + tx.vin[0].prevout.n = 0; + tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].scriptSig << OP_1; + tx.vout.resize(1); + tx.vout[0].nValue = 1 * CENT; + tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + + LOCK(cs_orphancache); + AddOrphanTx(tx, i); + } + + { + LOCK(cs_orphancache); + LimitOrphanTxSize(50, 8000); + BOOST_CHECK_EQUAL(mapOrphanTransactions.size(), 50); + LimitOrphanTxSize(50, 6300); + BOOST_CHECK(mapOrphanTransactions.size() <= 49); + LimitOrphanTxSize(50, 1000); + BOOST_CHECK(mapOrphanTransactions.size() <= 8); + LimitOrphanTxSize(50, 0); + BOOST_CHECK(mapOrphanTransactions.empty()); + } + // 50 orphan transactions: for (int i = 0; i < 50; i++) { - CTransaction tx; + CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].prevout.n = 0; tx.vin[0].prevout.hash = GetRandHash(); tx.vin[0].scriptSig << OP_1; tx.vout.resize(1); - tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); + tx.vout[0].nValue = 1 * CENT; + tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); - CDataStream ds(SER_DISK, CLIENT_VERSION); - ds << tx; - AddOrphanTx(ds); + LOCK(cs_orphancache); + AddOrphanTx(tx, i); } // ... and 50 that depend on other orphans: @@ -172,29 +366,28 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) { CTransaction txPrev = RandomOrphan(); - CTransaction tx; + CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].prevout.n = 0; tx.vin[0].prevout.hash = txPrev.GetHash(); tx.vout.resize(1); - tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); + tx.vout[0].nValue = 1 * CENT; + tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); SignSignature(keystore, txPrev, tx, 0); - CDataStream ds(SER_DISK, CLIENT_VERSION); - ds << tx; - AddOrphanTx(ds); + LOCK(cs_orphancache); + AddOrphanTx(tx, i); } // This really-big orphan should be ignored: - for (int i = 0; i < 10; i++) + for (int i = 0; i < 1; i++) { CTransaction txPrev = RandomOrphan(); - CTransaction tx; + CMutableTransaction tx; tx.vout.resize(1); - tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); + tx.vout[0].nValue = 1 * CENT; + tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); tx.vin.resize(500); for (unsigned int j = 0; j < tx.vin.size(); j++) { @@ -207,107 +400,80 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) for (unsigned int j = 1; j < tx.vin.size(); j++) tx.vin[j].scriptSig = tx.vin[0].scriptSig; - CDataStream ds(SER_DISK, CLIENT_VERSION); - ds << tx; - BOOST_CHECK(!AddOrphanTx(ds)); + LOCK(cs_orphancache); + // BU, we keep orphans up to the configured memory limit to help xthin compression so this should succeed + // whereas it fails in other clients + BOOST_CHECK(AddOrphanTx(tx, i)); } - // Test LimitOrphanTxSize() function: - LimitOrphanTxSize(40); - BOOST_CHECK(mapOrphanTransactions.size() <= 40); - LimitOrphanTxSize(10); - BOOST_CHECK(mapOrphanTransactions.size() <= 10); - LimitOrphanTxSize(0); - BOOST_CHECK(mapOrphanTransactions.empty()); - BOOST_CHECK(mapOrphanTransactionsByPrev.empty()); -} - -BOOST_AUTO_TEST_CASE(DoS_checkSig) -{ - // Test signature caching code (see key.cpp Verify() methods) - - CKey key; - key.MakeNewKey(true); - CBasicKeyStore keystore; - keystore.AddKey(key); - - // 100 orphan transactions: - static const int NPREV=100; - CTransaction orphans[NPREV]; - for (int i = 0; i < NPREV; i++) + // Test LimitOrphanTxSize() function: limit by number of txns { - CTransaction& tx = orphans[i]; - tx.vin.resize(1); - tx.vin[0].prevout.n = 0; - tx.vin[0].prevout.hash = GetRandHash(); - tx.vin[0].scriptSig << OP_1; - tx.vout.resize(1); - tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); - - CDataStream ds(SER_DISK, CLIENT_VERSION); - ds << tx; - AddOrphanTx(ds); + LOCK(cs_orphancache); + LimitOrphanTxSize(40, 10000000); + BOOST_CHECK_EQUAL(mapOrphanTransactions.size(), 40); + LimitOrphanTxSize(10, 10000000); + BOOST_CHECK_EQUAL(mapOrphanTransactions.size(), 10); + LimitOrphanTxSize(0, 10000000); + BOOST_CHECK(mapOrphanTransactions.empty()); + BOOST_CHECK(mapOrphanTransactionsByPrev.empty()); } - // Create a transaction that depends on orphans: - CTransaction tx; - tx.vout.resize(1); - tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); - tx.vin.resize(NPREV); - for (unsigned int j = 0; j < tx.vin.size(); j++) + // Test EraseOrphansByTime(): { - tx.vin[j].prevout.n = 0; - tx.vin[j].prevout.hash = orphans[j].GetHash(); + LOCK(cs_orphancache); + int64_t nStartTime = GetTime(); + nLastOrphanCheck = nStartTime; + SetMockTime(nStartTime); // Overrides future calls to GetTime() + for (int i = 0; i < 50; i++) + { + CMutableTransaction tx; + tx.vin.resize(1); + tx.vin[0].prevout.n = 0; + tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].scriptSig << OP_1; + tx.vout.resize(1); + tx.vout[0].nValue = 1 * CENT; + tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + + AddOrphanTx(tx, i); + } + BOOST_CHECK(mapOrphanTransactions.size() == 50); + EraseOrphansByTime(); + BOOST_CHECK(mapOrphanTransactions.size() == 50); + + // Advance the clock 1 minute + SetMockTime(nStartTime + 60); + EraseOrphansByTime(); + BOOST_CHECK(mapOrphanTransactions.size() == 50); + + // Advance the clock 10 minutes + SetMockTime(nStartTime + 60 * 10); + EraseOrphansByTime(); + BOOST_CHECK(mapOrphanTransactions.size() == 50); + + // Advance the clock 1 hour + SetMockTime(nStartTime + 60 * 60); + EraseOrphansByTime(); + BOOST_CHECK(mapOrphanTransactions.size() == 50); + + // Advance the clock DEFAULT_ORPHANPOOL_EXPIRY hours + SetMockTime(nStartTime + 60 * 60 * DEFAULT_ORPHANPOOL_EXPIRY); + EraseOrphansByTime(); + BOOST_CHECK(mapOrphanTransactions.size() == 50); + + /** Test the boundary where orphans should get purged. **/ + // Advance the clock DEFAULT_ORPHANPOOL_EXPIRY hours plus 4 minutes 59 seconds + SetMockTime(nStartTime + 60 * 60 * DEFAULT_ORPHANPOOL_EXPIRY + 299); + EraseOrphansByTime(); + BOOST_CHECK(mapOrphanTransactions.size() == 50); + + // Advance the clock DEFAULT_ORPHANPOOL_EXPIRY hours plus 5 minutes + SetMockTime(nStartTime + 60 * 60 * DEFAULT_ORPHANPOOL_EXPIRY + 300); + EraseOrphansByTime(); + BOOST_CHECK(mapOrphanTransactions.size() == 0); + + SetMockTime(0); } - // Creating signatures primes the cache: - boost::posix_time::ptime mst1 = boost::posix_time::microsec_clock::local_time(); - for (unsigned int j = 0; j < tx.vin.size(); j++) - BOOST_CHECK(SignSignature(keystore, orphans[j], tx, j)); - boost::posix_time::ptime mst2 = boost::posix_time::microsec_clock::local_time(); - boost::posix_time::time_duration msdiff = mst2 - mst1; - long nOneValidate = msdiff.total_milliseconds(); - if (fDebug) printf("DoS_Checksig sign: %ld\n", nOneValidate); - - // ... now validating repeatedly should be quick: - // 2.8GHz machine, -g build: Sign takes ~760ms, - // uncached Verify takes ~250ms, cached Verify takes ~50ms - // (for 100 single-signature inputs) - mst1 = boost::posix_time::microsec_clock::local_time(); - for (unsigned int i = 0; i < 5; i++) - for (unsigned int j = 0; j < tx.vin.size(); j++) - BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL)); - mst2 = boost::posix_time::microsec_clock::local_time(); - msdiff = mst2 - mst1; - long nManyValidate = msdiff.total_milliseconds(); - if (fDebug) printf("DoS_Checksig five: %ld\n", nManyValidate); - - BOOST_CHECK_MESSAGE(nManyValidate < nOneValidate, "Signature cache timing failed"); - - // Empty a signature, validation should fail: - CScript save = tx.vin[0].scriptSig; - tx.vin[0].scriptSig = CScript(); - BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL)); - tx.vin[0].scriptSig = save; - - // Swap signatures, validation should fail: - std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig); - BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL)); - BOOST_CHECK(!VerifySignature(orphans[1], tx, 1, true, SIGHASH_ALL)); - std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig); - - // Exercise -maxsigcachesize code: - mapArgs["-maxsigcachesize"] = "10"; - // Generate a new, different signature for vin[0] to trigger cache clear: - CScript oldSig = tx.vin[0].scriptSig; - BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0)); - BOOST_CHECK(tx.vin[0].scriptSig != oldSig); - for (unsigned int j = 0; j < tx.vin.size(); j++) - BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL)); - mapArgs.erase("-maxsigcachesize"); - - LimitOrphanTxSize(0); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/Makefile b/src/test/Makefile new file mode 100644 index 00000000..87bf73fe --- /dev/null +++ b/src/test/Makefile @@ -0,0 +1,6 @@ +all: + $(MAKE) -C .. bitcoin_test +clean: + $(MAKE) -C .. bitcoin_test_clean +check: + $(MAKE) -C .. bitcoin_test_check diff --git a/src/test/README b/src/test/README.md similarity index 66% rename from src/test/README rename to src/test/README.md index 77f7faa8..b2d6be14 100644 --- a/src/test/README +++ b/src/test/README.md @@ -1,3 +1,4 @@ +# Notes The sources in this directory are unit test cases. Boost includes a unit testing framework, and since bitcoin already uses boost, it makes sense to simply use this framework rather than require developers to @@ -15,7 +16,20 @@ their tests in a test suite called "_tests". For an examples of this pattern, examine uint160_tests.cpp and uint256_tests.cpp. +Add the source files to /src/Makefile.test.include to add them to the build. + For further reading, I found the following website to be helpful in explaining how the boost unit test framework works: +[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/). + +test_bitcoin has some built-in command-line arguments; for +example, to run just the getarg_tests verbosely: + + test_bitcoin --log_level=all --run_test=getarg_tests + +... or to run just the doubledash test: + + test_bitcoin --run_test=getarg_tests/doubledash + +Run test_bitcoin --help for the full list. -http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/ diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp new file mode 100644 index 00000000..c699701e --- /dev/null +++ b/src/test/addrman_tests.cpp @@ -0,0 +1,514 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "addrman.h" +#include "test/test_bitcoin.h" +#include +#include + +#include "hash.h" +#include "random.h" + +using namespace std; + +class CAddrManTest : public CAddrMan +{ + uint64_t state; + +public: + CAddrManTest() { state = 1; } + //! Ensure that bucket placement is always the same for testing purposes. + void MakeDeterministic() + { + nKey.SetNull(); + seed_insecure_rand(true); + } + + int RandomInt(int nMax) + { + state = (CHashWriter(SER_GETHASH, 0) << state).GetHash().GetCheapHash(); + return (unsigned int)(state % nMax); + } + + CAddrInfo *Find(const CNetAddr &addr, int *pnId = NULL) { return CAddrMan::Find(addr, pnId); } + CAddrInfo *Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = NULL) + { + return CAddrMan::Create(addr, addrSource, pnId); + } + + void Delete(int nId) { CAddrMan::Delete(nId); } +}; + +BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(addrman_simple) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + // Test 1: Does Addrman respond correctly when empty. + BOOST_CHECK(addrman.size() == 0); + CAddrInfo addr_null = addrman.Select(); + BOOST_CHECK(addr_null.ToString() == "[::]:0"); + + // Test 2: Does Addrman::Add work as expected. + CService addr1 = CService("250.1.1.1", 8333); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 1); + CAddrInfo addr_ret1 = addrman.Select(); + BOOST_CHECK(addr_ret1.ToString() == "250.1.1.1:8333"); + + // Test 3: Does IP address deduplication work correctly. + // Expected dup IP should not be added. + CService addr1_dup = CService("250.1.1.1", 8333); + addrman.Add(CAddress(addr1_dup), source); + BOOST_CHECK(addrman.size() == 1); + + + // Test 5: New table has one addr and we add a diff addr we should + // have two addrs. + CService addr2 = CService("250.1.1.2", 8333); + addrman.Add(CAddress(addr2), source); + BOOST_CHECK(addrman.size() == 2); + + // Test 6: AddrMan::Clear() should empty the new table. + addrman.Clear(); + BOOST_CHECK(addrman.size() == 0); + CAddrInfo addr_null2 = addrman.Select(); + BOOST_CHECK(addr_null2.ToString() == "[::]:0"); +} + +BOOST_AUTO_TEST_CASE(addrman_ports) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + BOOST_CHECK(addrman.size() == 0); + + // Test 7; Addr with same IP but diff port does not replace existing addr. + CService addr1 = CService("250.1.1.1", 8333); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 1); + + CService addr1_port = CService("250.1.1.1", 8334); + addrman.Add(CAddress(addr1_port), source); + BOOST_CHECK(addrman.size() == 1); + CAddrInfo addr_ret2 = addrman.Select(); + BOOST_CHECK(addr_ret2.ToString() == "250.1.1.1:8333"); + + // Test 8: Add same IP but diff port to tried table, it doesn't get added. + // Perhaps this is not ideal behavior but it is the current behavior. + addrman.Good(CAddress(addr1_port)); + BOOST_CHECK(addrman.size() == 1); + bool newOnly = true; + CAddrInfo addr_ret3 = addrman.Select(newOnly); + BOOST_CHECK(addr_ret3.ToString() == "250.1.1.1:8333"); +} + + +BOOST_AUTO_TEST_CASE(addrman_select) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + // Test 9: Select from new with 1 addr in new. + CService addr1 = CService("250.1.1.1", 8333); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 1); + + bool newOnly = true; + CAddrInfo addr_ret1 = addrman.Select(newOnly); + BOOST_CHECK(addr_ret1.ToString() == "250.1.1.1:8333"); + + // Test 10: move addr to tried, select from new expected nothing returned. + addrman.Good(CAddress(addr1)); + BOOST_CHECK(addrman.size() == 1); + CAddrInfo addr_ret2 = addrman.Select(newOnly); + BOOST_CHECK(addr_ret2.ToString() == "[::]:0"); + + CAddrInfo addr_ret3 = addrman.Select(); + BOOST_CHECK(addr_ret3.ToString() == "250.1.1.1:8333"); + + BOOST_CHECK(addrman.size() == 1); + + + // Add three addresses to new table. + CService addr2 = CService("250.3.1.1", 8333); + CService addr3 = CService("250.3.2.2", 9999); + CService addr4 = CService("250.3.3.3", 9999); + + addrman.Add(CAddress(addr2), CService("250.3.1.1", 8333)); + addrman.Add(CAddress(addr3), CService("250.3.1.1", 8333)); + addrman.Add(CAddress(addr4), CService("250.4.1.1", 8333)); + + // Add three addresses to tried table. + CService addr5 = CService("250.4.4.4", 8333); + CService addr6 = CService("250.4.5.5", 7777); + CService addr7 = CService("250.4.6.6", 8333); + + addrman.Add(CAddress(addr5), CService("250.3.1.1", 8333)); + addrman.Good(CAddress(addr5)); + addrman.Add(CAddress(addr6), CService("250.3.1.1", 8333)); + addrman.Good(CAddress(addr6)); + addrman.Add(CAddress(addr7), CService("250.1.1.3", 8333)); + addrman.Good(CAddress(addr7)); + + // Test 11: 6 addrs + 1 addr from last test = 7. + BOOST_CHECK(addrman.size() == 7); + + // Test 12: Select pulls from new and tried regardless of port number. + BOOST_CHECK(addrman.Select().ToString() == "250.4.6.6:8333"); + BOOST_CHECK(addrman.Select().ToString() == "250.3.2.2:9999"); + BOOST_CHECK(addrman.Select().ToString() == "250.3.3.3:9999"); + BOOST_CHECK(addrman.Select().ToString() == "250.4.4.4:8333"); +} + +BOOST_AUTO_TEST_CASE(addrman_new_collisions) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + BOOST_CHECK(addrman.size() == 0); + + for (unsigned int i = 1; i < 18; i++) + { + CService addr = CService("250.1.1." + boost::to_string(i)); + addrman.Add(CAddress(addr), source); + + // Test 13: No collision in new table yet. + BOOST_CHECK(addrman.size() == i); + } + + // Test 14: new table collision! + CService addr1 = CService("250.1.1.18"); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 17); + + CService addr2 = CService("250.1.1.19"); + addrman.Add(CAddress(addr2), source); + BOOST_CHECK(addrman.size() == 18); +} + +BOOST_AUTO_TEST_CASE(addrman_tried_collisions) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + BOOST_CHECK(addrman.size() == 0); + + for (unsigned int i = 1; i < 80; i++) + { + CService addr = CService("250.1.1." + boost::to_string(i)); + addrman.Add(CAddress(addr), source); + addrman.Good(CAddress(addr)); + + // Test 15: No collision in tried table yet. + BOOST_TEST_MESSAGE(addrman.size()); + BOOST_CHECK(addrman.size() == i); + } + + // Test 16: tried table collision! + CService addr1 = CService("250.1.1.80"); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 79); + + CService addr2 = CService("250.1.1.81"); + addrman.Add(CAddress(addr2), source); + BOOST_CHECK(addrman.size() == 80); +} + +BOOST_AUTO_TEST_CASE(addrman_find) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + BOOST_CHECK(addrman.size() == 0); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CAddress addr2 = CAddress(CService("250.1.2.1", 9999)); + CAddress addr3 = CAddress(CService("251.255.2.1", 8333)); + + CNetAddr source1 = CNetAddr("250.1.2.1"); + CNetAddr source2 = CNetAddr("250.1.2.2"); + + addrman.Add(addr1, source1); + addrman.Add(addr2, source2); + addrman.Add(addr3, source1); + + // Test 17: ensure Find returns an IP matching what we searched on. + CAddrInfo *info1 = addrman.Find(addr1); + BOOST_CHECK(info1); + if (info1) + BOOST_CHECK(info1->ToString() == "250.1.2.1:8333"); + + // Test 18; Find does not discriminate by port number. + CAddrInfo *info2 = addrman.Find(addr2); + BOOST_CHECK(info2); + if (info2) + BOOST_CHECK(info2->ToString() == info1->ToString()); + + // Test 19: Find returns another IP matching what we searched on. + CAddrInfo *info3 = addrman.Find(addr3); + BOOST_CHECK(info3); + if (info3) + BOOST_CHECK(info3->ToString() == "251.255.2.1:8333"); +} + +BOOST_AUTO_TEST_CASE(addrman_create) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + BOOST_CHECK(addrman.size() == 0); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CNetAddr source1 = CNetAddr("250.1.2.1"); + + int nId; + CAddrInfo *pinfo = addrman.Create(addr1, source1, &nId); + + // Test 20: The result should be the same as the input addr. + BOOST_CHECK(pinfo->ToString() == "250.1.2.1:8333"); + + CAddrInfo *info2 = addrman.Find(addr1); + BOOST_CHECK(info2->ToString() == "250.1.2.1:8333"); +} + + +BOOST_AUTO_TEST_CASE(addrman_delete) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + BOOST_CHECK(addrman.size() == 0); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CNetAddr source1 = CNetAddr("250.1.2.1"); + + int nId; + addrman.Create(addr1, source1, &nId); + + // Test 21: Delete should actually delete the addr. + BOOST_CHECK(addrman.size() == 1); + addrman.Delete(nId); + BOOST_CHECK(addrman.size() == 0); + CAddrInfo *info2 = addrman.Find(addr1); + BOOST_CHECK(info2 == NULL); +} + +BOOST_AUTO_TEST_CASE(addrman_getaddr) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + // Test 22: Sanity check, GetAddr should never return anything if addrman + // is empty. + BOOST_CHECK(addrman.size() == 0); + vector vAddr1 = addrman.GetAddr(); + BOOST_CHECK(vAddr1.size() == 0); + + CAddress addr1 = CAddress(CService("250.250.2.1", 8333)); + addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false + CAddress addr2 = CAddress(CService("250.251.2.2", 9999)); + addr2.nTime = GetAdjustedTime(); + CAddress addr3 = CAddress(CService("251.252.2.3", 8333)); + addr3.nTime = GetAdjustedTime(); + CAddress addr4 = CAddress(CService("252.253.3.4", 8333)); + addr4.nTime = GetAdjustedTime(); + CAddress addr5 = CAddress(CService("252.254.4.5", 8333)); + addr5.nTime = GetAdjustedTime(); + CNetAddr source1 = CNetAddr("250.1.2.1"); + CNetAddr source2 = CNetAddr("250.2.3.3"); + + // Test 23: Ensure GetAddr works with new addresses. + addrman.Add(addr1, source1); + addrman.Add(addr2, source2); + addrman.Add(addr3, source1); + addrman.Add(addr4, source2); + addrman.Add(addr5, source1); + + // GetAddr returns 23% of addresses, 23% of 5 is 1 rounded down. + BOOST_CHECK(addrman.GetAddr().size() == 1); + + // Test 24: Ensure GetAddr works with new and tried addresses. + addrman.Good(CAddress(addr1)); + addrman.Good(CAddress(addr2)); + BOOST_CHECK(addrman.GetAddr().size() == 1); + + // Test 25: Ensure GetAddr still returns 23% when addrman has many addrs. + for (unsigned int i = 1; i < (8 * 256); i++) + { + int octet1 = i % 256; + int octet2 = (i / 256) % 256; + int octet3 = (i / (256 * 2)) % 256; + string strAddr = + boost::to_string(octet1) + "." + boost::to_string(octet2) + "." + boost::to_string(octet3) + ".23"; + CAddress addr = CAddress(CService(strAddr)); + + // Ensure that for all addrs in addrman, isTerrible == false. + addr.nTime = GetAdjustedTime(); + addrman.Add(addr, CNetAddr(strAddr)); + if (i % 8 == 0) + addrman.Good(addr); + } + vector vAddr = addrman.GetAddr(); + + size_t percent23 = (addrman.size() * 23) / 100; + BOOST_CHECK(vAddr.size() == percent23); + BOOST_CHECK(vAddr.size() == 461); + // (Addrman.size() < number of addresses added) due to address collisons. + BOOST_CHECK(addrman.size() == 2007); +} + + +BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CAddress addr1 = CAddress(CService("250.1.1.1", 8333)); + CAddress addr2 = CAddress(CService("250.1.1.1", 9999)); + + CNetAddr source1 = CNetAddr("250.1.1.1"); + + + CAddrInfo info1 = CAddrInfo(addr1, source1); + + uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); + uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); + + + BOOST_CHECK(info1.GetTriedBucket(nKey1) == 40); + + // Test 26: Make sure key actually randomizes bucket placement. A fail on + // this test could be a security issue. + BOOST_CHECK(info1.GetTriedBucket(nKey1) != info1.GetTriedBucket(nKey2)); + + // Test 27: Two addresses with same IP but different ports can map to + // different buckets because they have different keys. + CAddrInfo info2 = CAddrInfo(addr2, source1); + + BOOST_CHECK(info1.GetKey() != info2.GetKey()); + BOOST_CHECK(info1.GetTriedBucket(nKey1) != info2.GetTriedBucket(nKey1)); + + set buckets; + for (int i = 0; i < 255; i++) + { + CAddrInfo infoi = + CAddrInfo(CAddress(CService("250.1.1." + boost::to_string(i))), CNetAddr("250.1.1." + boost::to_string(i))); + int bucket = infoi.GetTriedBucket(nKey1); + buckets.insert(bucket); + } + // Test 28: IP addresses in the same group (\16 prefix for IPv4) should + // never get more than 8 buckets + BOOST_CHECK(buckets.size() == 8); + + buckets.clear(); + for (int j = 0; j < 255; j++) + { + CAddrInfo infoj = CAddrInfo( + CAddress(CService("250." + boost::to_string(j) + ".1.1")), CNetAddr("250." + boost::to_string(j) + ".1.1")); + int bucket = infoj.GetTriedBucket(nKey1); + buckets.insert(bucket); + } + // Test 29: IP addresses in the different groups should map to more than + // 8 buckets. + BOOST_CHECK(buckets.size() == 160); +} + +BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CAddress addr2 = CAddress(CService("250.1.2.1", 9999)); + + CNetAddr source1 = CNetAddr("250.1.2.1"); + + CAddrInfo info1 = CAddrInfo(addr1, source1); + + uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); + uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); + + BOOST_CHECK(info1.GetNewBucket(nKey1) == 786); + + // Test 30: Make sure key actually randomizes bucket placement. A fail on + // this test could be a security issue. + BOOST_CHECK(info1.GetNewBucket(nKey1) != info1.GetNewBucket(nKey2)); + + // Test 31: Ports should not effect bucket placement in the addr + CAddrInfo info2 = CAddrInfo(addr2, source1); + BOOST_CHECK(info1.GetKey() != info2.GetKey()); + BOOST_CHECK(info1.GetNewBucket(nKey1) == info2.GetNewBucket(nKey1)); + + set buckets; + for (int i = 0; i < 255; i++) + { + CAddrInfo infoi = + CAddrInfo(CAddress(CService("250.1.1." + boost::to_string(i))), CNetAddr("250.1.1." + boost::to_string(i))); + int bucket = infoi.GetNewBucket(nKey1); + buckets.insert(bucket); + } + // Test 32: IP addresses in the same group (\16 prefix for IPv4) should + // always map to the same bucket. + BOOST_CHECK(buckets.size() == 1); + + buckets.clear(); + for (int j = 0; j < 4 * 255; j++) + { + CAddrInfo infoj = + CAddrInfo(CAddress(CService(boost::to_string(250 + (j / 255)) + "." + boost::to_string(j % 256) + ".1.1")), + CNetAddr("251.4.1.1")); + int bucket = infoj.GetNewBucket(nKey1); + buckets.insert(bucket); + } + // Test 33: IP addresses in the same source groups should map to no more + // than 64 buckets. + BOOST_CHECK(buckets.size() <= 64); + + buckets.clear(); + for (int p = 0; p < 255; p++) + { + CAddrInfo infoj = CAddrInfo(CAddress(CService("250.1.1.1")), CNetAddr("250." + boost::to_string(p) + ".1.1")); + int bucket = infoj.GetNewBucket(nKey1); + buckets.insert(bucket); + } + // Test 34: IP addresses in the different source groups should map to more + // than 64 buckets. + BOOST_CHECK(buckets.size() > 64); +} +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp new file mode 100644 index 00000000..67e38bae --- /dev/null +++ b/src/test/alert_tests.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2013-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// Unit tests for alert system + +#include "chainparams.h" +#include "main.h" // For PartitionCheck + +#include "test/test_bitcoin.h" +#include "test/testutil.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(Alert_tests, TestingSetup) + + +static bool falseFunc() { return false; } +BOOST_AUTO_TEST_CASE(PartitionAlert) +{ + // Test PartitionCheck + CCriticalSection csDummy; + CBlockIndex indexDummy[100]; + CChainParams ¶ms = Params(CBaseChainParams::MAIN); + int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing; + + // Generate fake blockchain timestamps relative to + // an arbitrary time: + int64_t now = 1427379054; + SetMockTime(now); + for (int i = 0; i < 100; i++) + { + indexDummy[i].phashBlock = NULL; + if (i == 0) + indexDummy[i].pprev = NULL; + else + indexDummy[i].pprev = &indexDummy[i - 1]; + indexDummy[i].nHeight = i; + indexDummy[i].nTime = now - (100 - i) * nPowTargetSpacing; + // Other members don't matter, the partition check code doesn't + // use them + } + + strMiscWarning = ""; + + // Test 1: chain with blocks every nPowTargetSpacing seconds, + // as normal, no worries: + PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); + BOOST_CHECK_MESSAGE(strMiscWarning.empty(), strMiscWarning); + + // Test 2: go 3.5 hours without a block, expect a warning: + now += 3 * 60 * 60 + 30 * 60; + SetMockTime(now); + PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); + BOOST_CHECK(!strMiscWarning.empty()); + BOOST_TEST_MESSAGE(std::string("Got alert text: ") + strMiscWarning); + strMiscWarning = ""; + + // Test 3: test the "partition alerts only go off once per day" + // code: + now += 60 * 10; + SetMockTime(now); + PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); + BOOST_CHECK(strMiscWarning.empty()); + + // Test 4: get 2.5 times as many blocks as expected: + now += 60 * 60 * 24; // Pretend it is a day later + SetMockTime(now); + int64_t quickSpacing = nPowTargetSpacing * 2 / 5; + for (int i = 0; i < 100; i++) // Tweak chain timestamps: + indexDummy[i].nTime = now - (100 - i) * quickSpacing; + PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); + BOOST_CHECK(!strMiscWarning.empty()); + BOOST_TEST_MESSAGE(std::string("Got alert text: ") + strMiscWarning); + strMiscWarning = ""; + + SetMockTime(0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index d5cb8e81..73f8fb54 100644 --- a/src/test/allocator_tests.cpp +++ b/src/test/allocator_tests.cpp @@ -1,10 +1,16 @@ -#include +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "init.h" -#include "main.h" #include "util.h" -BOOST_AUTO_TEST_SUITE(allocator_tests) +#include "support/allocators/secure.h" +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(allocator_tests, BasicTestingSetup) // Dummy memory page locker for platform independent tests static const void *last_lock_addr, *last_unlock_addr; @@ -36,80 +42,79 @@ BOOST_AUTO_TEST_CASE(test_LockedPageManagerBase) /* Try large number of small objects */ addr = 0; - for(int i=0; i<1000; ++i) + for (int i = 0; i < 1000; ++i) { - lpm.LockRange(reinterpret_cast(addr), 33); + lpm.LockRange(reinterpret_cast(addr), 33); addr += 33; } /* Try small number of page-sized objects, straddling two pages */ - addr = test_page_size*100 + 53; - for(int i=0; i<100; ++i) + addr = test_page_size * 100 + 53; + for (int i = 0; i < 100; ++i) { - lpm.LockRange(reinterpret_cast(addr), test_page_size); + lpm.LockRange(reinterpret_cast(addr), test_page_size); addr += test_page_size; } /* Try small number of page-sized objects aligned to exactly one page */ - addr = test_page_size*300; - for(int i=0; i<100; ++i) + addr = test_page_size * 300; + for (int i = 0; i < 100; ++i) { - lpm.LockRange(reinterpret_cast(addr), test_page_size); + lpm.LockRange(reinterpret_cast(addr), test_page_size); addr += test_page_size; } /* one very large object, straddling pages */ - lpm.LockRange(reinterpret_cast(test_page_size*600+1), test_page_size*500); - BOOST_CHECK(last_lock_addr == reinterpret_cast(test_page_size*(600+500))); + lpm.LockRange(reinterpret_cast(test_page_size * 600 + 1), test_page_size * 500); + BOOST_CHECK(last_lock_addr == reinterpret_cast(test_page_size * (600 + 500))); /* one very large object, page aligned */ - lpm.LockRange(reinterpret_cast(test_page_size*1200), test_page_size*500-1); - BOOST_CHECK(last_lock_addr == reinterpret_cast(test_page_size*(1200+500-1))); + lpm.LockRange(reinterpret_cast(test_page_size * 1200), test_page_size * 500 - 1); + BOOST_CHECK(last_lock_addr == reinterpret_cast(test_page_size * (1200 + 500 - 1))); - BOOST_CHECK(lpm.GetLockedPageCount() == ( - (1000*33+test_page_size-1)/test_page_size + // small objects - 101 + 100 + // page-sized objects - 501 + 500)); // large objects - BOOST_CHECK((last_lock_len & (test_page_size-1)) == 0); // always lock entire pages + BOOST_CHECK(lpm.GetLockedPageCount() == ((1000 * 33 + test_page_size - 1) / test_page_size + // small objects + 101 + 100 + // page-sized objects + 501 + 500)); // large objects + BOOST_CHECK((last_lock_len & (test_page_size - 1)) == 0); // always lock entire pages BOOST_CHECK(last_unlock_len == 0); // nothing unlocked yet /* And unlock again */ addr = 0; - for(int i=0; i<1000; ++i) + for (int i = 0; i < 1000; ++i) { - lpm.UnlockRange(reinterpret_cast(addr), 33); + lpm.UnlockRange(reinterpret_cast(addr), 33); addr += 33; } - addr = test_page_size*100 + 53; - for(int i=0; i<100; ++i) + addr = test_page_size * 100 + 53; + for (int i = 0; i < 100; ++i) { - lpm.UnlockRange(reinterpret_cast(addr), test_page_size); + lpm.UnlockRange(reinterpret_cast(addr), test_page_size); addr += test_page_size; } - addr = test_page_size*300; - for(int i=0; i<100; ++i) + addr = test_page_size * 300; + for (int i = 0; i < 100; ++i) { - lpm.UnlockRange(reinterpret_cast(addr), test_page_size); + lpm.UnlockRange(reinterpret_cast(addr), test_page_size); addr += test_page_size; } - lpm.UnlockRange(reinterpret_cast(test_page_size*600+1), test_page_size*500); - lpm.UnlockRange(reinterpret_cast(test_page_size*1200), test_page_size*500-1); + lpm.UnlockRange(reinterpret_cast(test_page_size * 600 + 1), test_page_size * 500); + lpm.UnlockRange(reinterpret_cast(test_page_size * 1200), test_page_size * 500 - 1); /* Check that everything is released */ BOOST_CHECK(lpm.GetLockedPageCount() == 0); /* A few and unlocks of size zero (should have no effect) */ addr = 0; - for(int i=0; i<1000; ++i) + for (int i = 0; i < 1000; ++i) { - lpm.LockRange(reinterpret_cast(addr), 0); + lpm.LockRange(reinterpret_cast(addr), 0); addr += 1; } BOOST_CHECK(lpm.GetLockedPageCount() == 0); addr = 0; - for(int i=0; i<1000; ++i) + for (int i = 0; i < 1000; ++i) { - lpm.UnlockRange(reinterpret_cast(addr), 0); + lpm.UnlockRange(reinterpret_cast(addr), 0); addr += 1; } BOOST_CHECK(lpm.GetLockedPageCount() == 0); - BOOST_CHECK((last_unlock_len & (test_page_size-1)) == 0); // always unlock entire pages + BOOST_CHECK((last_unlock_len & (test_page_size - 1)) == 0); // always unlock entire pages } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp new file mode 100644 index 00000000..cf3283f6 --- /dev/null +++ b/src/test/arith_uint256_tests.cpp @@ -0,0 +1,605 @@ +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "arith_uint256.h" +#include "test/test_bitcoin.h" +#include "uint256.h" +#include "version.h" +#include +#include +#include +#include +#include +#include +#include + +BOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup) + +/// Convert vector to arith_uint256, via uint256 blob +inline arith_uint256 arith_uint256V(const std::vector &vch) { return UintToArith256(uint256(vch)); } +const unsigned char R1Array[] = "\x9c\x52\x4a\xdb\xcf\x56\x11\x12\x2b\x29\x12\x5e\x5d\x35\xd2\xd2" + "\x22\x81\xaa\xb5\x33\xf0\x08\x32\xd5\x56\xb1\xf9\xea\xe5\x1d\x7d"; +const char R1ArrayHex[] = "7D1DE5EAF9B156D53208F033B5AA8122D2d2355d5e12292b121156cfdb4a529c"; +const double R1Ldouble = 0.4887374590559308955; // R1L equals roughly R1Ldouble * 2^256 +const arith_uint256 R1L = arith_uint256V(std::vector(R1Array, R1Array + 32)); +const uint64_t R1LLow64 = 0x121156cfdb4a529cULL; + +const unsigned char R2Array[] = "\x70\x32\x1d\x7c\x47\xa5\x6b\x40\x26\x7e\x0a\xc3\xa6\x9c\xb6\xbf" + "\x13\x30\x47\xa3\x19\x2d\xda\x71\x49\x13\x72\xf0\xb4\xca\x81\xd7"; +const arith_uint256 R2L = arith_uint256V(std::vector(R2Array, R2Array + 32)); + +const char R1LplusR2L[] = "549FB09FEA236A1EA3E31D4D58F1B1369288D204211CA751527CFC175767850C"; + +const unsigned char ZeroArray[] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; +const arith_uint256 ZeroL = arith_uint256V(std::vector(ZeroArray, ZeroArray + 32)); + +const unsigned char OneArray[] = "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; +const arith_uint256 OneL = arith_uint256V(std::vector(OneArray, OneArray + 32)); + +const unsigned char MaxArray[] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; +const arith_uint256 MaxL = arith_uint256V(std::vector(MaxArray, MaxArray + 32)); + +const arith_uint256 HalfL = (OneL << 255); +std::string ArrayToString(const unsigned char A[], unsigned int width) +{ + std::stringstream Stream; + Stream << std::hex; + for (unsigned int i = 0; i < width; ++i) + { + Stream << std::setw(2) << std::setfill('0') << (unsigned int)A[width - i - 1]; + } + return Stream.str(); +} + +BOOST_AUTO_TEST_CASE(basics) // constructors, equality, inequality +{ + BOOST_CHECK(1 == 0 + 1); + // constructor arith_uint256(vector): + BOOST_CHECK(R1L.ToString() == ArrayToString(R1Array, 32)); + BOOST_CHECK(R2L.ToString() == ArrayToString(R2Array, 32)); + BOOST_CHECK(ZeroL.ToString() == ArrayToString(ZeroArray, 32)); + BOOST_CHECK(OneL.ToString() == ArrayToString(OneArray, 32)); + BOOST_CHECK(MaxL.ToString() == ArrayToString(MaxArray, 32)); + BOOST_CHECK(OneL.ToString() != ArrayToString(ZeroArray, 32)); + + // == and != + BOOST_CHECK(R1L != R2L); + BOOST_CHECK(ZeroL != OneL); + BOOST_CHECK(OneL != ZeroL); + BOOST_CHECK(MaxL != ZeroL); + BOOST_CHECK(~MaxL == ZeroL); + BOOST_CHECK(((R1L ^ R2L) ^ R1L) == R2L); + + uint64_t Tmp64 = 0xc4dab720d9c7acaaULL; + for (unsigned int i = 0; i < 256; ++i) + { + BOOST_CHECK(ZeroL != (OneL << i)); + BOOST_CHECK((OneL << i) != ZeroL); + BOOST_CHECK(R1L != (R1L ^ (OneL << i))); + BOOST_CHECK(((arith_uint256(Tmp64) ^ (OneL << i)) != Tmp64)); + } + BOOST_CHECK(ZeroL == (OneL << 256)); + + // String Constructor and Copy Constructor + BOOST_CHECK(arith_uint256("0x" + R1L.ToString()) == R1L); + BOOST_CHECK(arith_uint256("0x" + R2L.ToString()) == R2L); + BOOST_CHECK(arith_uint256("0x" + ZeroL.ToString()) == ZeroL); + BOOST_CHECK(arith_uint256("0x" + OneL.ToString()) == OneL); + BOOST_CHECK(arith_uint256("0x" + MaxL.ToString()) == MaxL); + BOOST_CHECK(arith_uint256(R1L.ToString()) == R1L); + BOOST_CHECK(arith_uint256(" 0x" + R1L.ToString() + " ") == R1L); + BOOST_CHECK(arith_uint256("") == ZeroL); + BOOST_CHECK(R1L == arith_uint256(R1ArrayHex)); + BOOST_CHECK(arith_uint256(R1L) == R1L); + BOOST_CHECK((arith_uint256(R1L ^ R2L) ^ R2L) == R1L); + BOOST_CHECK(arith_uint256(ZeroL) == ZeroL); + BOOST_CHECK(arith_uint256(OneL) == OneL); + + // uint64_t constructor + BOOST_CHECK((R1L & arith_uint256("0xffffffffffffffff")) == arith_uint256(R1LLow64)); + BOOST_CHECK(ZeroL == arith_uint256(0)); + BOOST_CHECK(OneL == arith_uint256(1)); + BOOST_CHECK(arith_uint256("0xffffffffffffffff") = arith_uint256(0xffffffffffffffffULL)); + + // Assignment (from base_uint) + arith_uint256 tmpL = ~ZeroL; + BOOST_CHECK(tmpL == ~ZeroL); + tmpL = ~OneL; + BOOST_CHECK(tmpL == ~OneL); + tmpL = ~R1L; + BOOST_CHECK(tmpL == ~R1L); + tmpL = ~R2L; + BOOST_CHECK(tmpL == ~R2L); + tmpL = ~MaxL; + BOOST_CHECK(tmpL == ~MaxL); +} + +void shiftArrayRight(unsigned char *to, const unsigned char *from, unsigned int arrayLength, unsigned int bitsToShift) +{ + for (unsigned int T = 0; T < arrayLength; ++T) + { + unsigned int F = (T + bitsToShift / 8); + if (F < arrayLength) + to[T] = from[F] >> (bitsToShift % 8); + else + to[T] = 0; + if (F + 1 < arrayLength) + to[T] |= from[(F + 1)] << (8 - bitsToShift % 8); + } +} + +void shiftArrayLeft(unsigned char *to, const unsigned char *from, unsigned int arrayLength, unsigned int bitsToShift) +{ + for (unsigned int T = 0; T < arrayLength; ++T) + { + if (T >= bitsToShift / 8) + { + unsigned int F = T - bitsToShift / 8; + to[T] = from[F] << (bitsToShift % 8); + if (T >= bitsToShift / 8 + 1) + to[T] |= from[F - 1] >> (8 - bitsToShift % 8); + } + else + { + to[T] = 0; + } + } +} + +BOOST_AUTO_TEST_CASE(shifts) +{ // "<<" ">>" "<<=" ">>=" + unsigned char TmpArray[32]; + arith_uint256 TmpL; + for (unsigned int i = 0; i < 256; ++i) + { + shiftArrayLeft(TmpArray, OneArray, 32, i); + BOOST_CHECK(arith_uint256V(std::vector(TmpArray, TmpArray + 32)) == (OneL << i)); + TmpL = OneL; + TmpL <<= i; + BOOST_CHECK(TmpL == (OneL << i)); + BOOST_CHECK((HalfL >> (255 - i)) == (OneL << i)); + TmpL = HalfL; + TmpL >>= (255 - i); + BOOST_CHECK(TmpL == (OneL << i)); + + shiftArrayLeft(TmpArray, R1Array, 32, i); + BOOST_CHECK(arith_uint256V(std::vector(TmpArray, TmpArray + 32)) == (R1L << i)); + TmpL = R1L; + TmpL <<= i; + BOOST_CHECK(TmpL == (R1L << i)); + + shiftArrayRight(TmpArray, R1Array, 32, i); + BOOST_CHECK(arith_uint256V(std::vector(TmpArray, TmpArray + 32)) == (R1L >> i)); + TmpL = R1L; + TmpL >>= i; + BOOST_CHECK(TmpL == (R1L >> i)); + + shiftArrayLeft(TmpArray, MaxArray, 32, i); + BOOST_CHECK(arith_uint256V(std::vector(TmpArray, TmpArray + 32)) == (MaxL << i)); + TmpL = MaxL; + TmpL <<= i; + BOOST_CHECK(TmpL == (MaxL << i)); + + shiftArrayRight(TmpArray, MaxArray, 32, i); + BOOST_CHECK(arith_uint256V(std::vector(TmpArray, TmpArray + 32)) == (MaxL >> i)); + TmpL = MaxL; + TmpL >>= i; + BOOST_CHECK(TmpL == (MaxL >> i)); + } + arith_uint256 c1L = arith_uint256(0x0123456789abcdefULL); + arith_uint256 c2L = c1L << 128; + for (unsigned int i = 0; i < 128; ++i) + { + BOOST_CHECK((c1L << i) == (c2L >> (128 - i))); + } + for (unsigned int i = 128; i < 256; ++i) + { + BOOST_CHECK((c1L << i) == (c2L << (i - 128))); + } +} + +BOOST_AUTO_TEST_CASE(unaryOperators) // ! ~ - +{ + BOOST_CHECK(!ZeroL); + BOOST_CHECK(!(!OneL)); + for (unsigned int i = 0; i < 256; ++i) + BOOST_CHECK(!(!(OneL << i))); + BOOST_CHECK(!(!R1L)); + BOOST_CHECK(!(!MaxL)); + + BOOST_CHECK(~ZeroL == MaxL); + + unsigned char TmpArray[32]; + for (unsigned int i = 0; i < 32; ++i) + { + TmpArray[i] = ~R1Array[i]; + } + BOOST_CHECK(arith_uint256V(std::vector(TmpArray, TmpArray + 32)) == (~R1L)); + + BOOST_CHECK(-ZeroL == ZeroL); + BOOST_CHECK(-R1L == (~R1L) + 1); + for (unsigned int i = 0; i < 256; ++i) + BOOST_CHECK(-(OneL << i) == (MaxL << i)); +} + + +// Check if doing _A_ _OP_ _B_ results in the same as applying _OP_ onto each +// element of Aarray and Barray, and then converting the result into a arith_uint256. +#define CHECKBITWISEOPERATOR(_A_, _B_, _OP_) \ + for (unsigned int i = 0; i < 32; ++i) \ + { \ + TmpArray[i] = _A_##Array[i] _OP_ _B_##Array[i]; \ + } \ + BOOST_CHECK(arith_uint256V(std::vector(TmpArray, TmpArray + 32)) == (_A_##L _OP_ _B_##L)); + +#define CHECKASSIGNMENTOPERATOR(_A_, _B_, _OP_) \ + TmpL = _A_##L; \ + TmpL _OP_## = _B_##L; \ + BOOST_CHECK(TmpL == (_A_##L _OP_ _B_##L)); + +BOOST_AUTO_TEST_CASE(bitwiseOperators) +{ + unsigned char TmpArray[32]; + + CHECKBITWISEOPERATOR(R1, R2, |) + CHECKBITWISEOPERATOR(R1, R2, ^) + CHECKBITWISEOPERATOR(R1, R2, &) + CHECKBITWISEOPERATOR(R1, Zero, |) + CHECKBITWISEOPERATOR(R1, Zero, ^) + CHECKBITWISEOPERATOR(R1, Zero, &) + CHECKBITWISEOPERATOR(R1, Max, |) + CHECKBITWISEOPERATOR(R1, Max, ^) + CHECKBITWISEOPERATOR(R1, Max, &) + CHECKBITWISEOPERATOR(Zero, R1, |) + CHECKBITWISEOPERATOR(Zero, R1, ^) + CHECKBITWISEOPERATOR(Zero, R1, &) + CHECKBITWISEOPERATOR(Max, R1, |) + CHECKBITWISEOPERATOR(Max, R1, ^) + CHECKBITWISEOPERATOR(Max, R1, &) + + arith_uint256 TmpL; + CHECKASSIGNMENTOPERATOR(R1, R2, |) + CHECKASSIGNMENTOPERATOR(R1, R2, ^) + CHECKASSIGNMENTOPERATOR(R1, R2, &) + CHECKASSIGNMENTOPERATOR(R1, Zero, |) + CHECKASSIGNMENTOPERATOR(R1, Zero, ^) + CHECKASSIGNMENTOPERATOR(R1, Zero, &) + CHECKASSIGNMENTOPERATOR(R1, Max, |) + CHECKASSIGNMENTOPERATOR(R1, Max, ^) + CHECKASSIGNMENTOPERATOR(R1, Max, &) + CHECKASSIGNMENTOPERATOR(Zero, R1, |) + CHECKASSIGNMENTOPERATOR(Zero, R1, ^) + CHECKASSIGNMENTOPERATOR(Zero, R1, &) + CHECKASSIGNMENTOPERATOR(Max, R1, |) + CHECKASSIGNMENTOPERATOR(Max, R1, ^) + CHECKASSIGNMENTOPERATOR(Max, R1, &) + + uint64_t Tmp64 = 0xe1db685c9a0b47a2ULL; + TmpL = R1L; + TmpL |= Tmp64; + BOOST_CHECK(TmpL == (R1L | arith_uint256(Tmp64))); + TmpL = R1L; + TmpL |= 0; + BOOST_CHECK(TmpL == R1L); + TmpL ^= 0; + BOOST_CHECK(TmpL == R1L); + TmpL ^= Tmp64; + BOOST_CHECK(TmpL == (R1L ^ arith_uint256(Tmp64))); +} + +BOOST_AUTO_TEST_CASE(comparison) // <= >= < > +{ + arith_uint256 TmpL; + for (unsigned int i = 0; i < 256; ++i) + { + TmpL = OneL << i; + BOOST_CHECK(TmpL >= ZeroL && TmpL > ZeroL && ZeroL < TmpL && ZeroL <= TmpL); + BOOST_CHECK(TmpL >= 0 && TmpL > 0 && 0 < TmpL && 0 <= TmpL); + TmpL |= R1L; + BOOST_CHECK(TmpL >= R1L); + BOOST_CHECK((TmpL == R1L) != (TmpL > R1L)); + BOOST_CHECK((TmpL == R1L) || !(TmpL <= R1L)); + BOOST_CHECK(R1L <= TmpL); + BOOST_CHECK((R1L == TmpL) != (R1L < TmpL)); + BOOST_CHECK((TmpL == R1L) || !(R1L >= TmpL)); + BOOST_CHECK(!(TmpL < R1L)); + BOOST_CHECK(!(R1L > TmpL)); + } +} + +BOOST_AUTO_TEST_CASE(plusMinus) +{ + arith_uint256 TmpL = 0; + BOOST_CHECK(R1L + R2L == arith_uint256(R1LplusR2L)); + TmpL += R1L; + BOOST_CHECK(TmpL == R1L); + TmpL += R2L; + BOOST_CHECK(TmpL == R1L + R2L); + BOOST_CHECK(OneL + MaxL == ZeroL); + BOOST_CHECK(MaxL + OneL == ZeroL); + for (unsigned int i = 1; i < 256; ++i) + { + BOOST_CHECK((MaxL >> i) + OneL == (HalfL >> (i - 1))); + BOOST_CHECK(OneL + (MaxL >> i) == (HalfL >> (i - 1))); + TmpL = (MaxL >> i); + TmpL += OneL; + BOOST_CHECK(TmpL == (HalfL >> (i - 1))); + TmpL = (MaxL >> i); + TmpL += 1; + BOOST_CHECK(TmpL == (HalfL >> (i - 1))); + TmpL = (MaxL >> i); + BOOST_CHECK(TmpL++ == (MaxL >> i)); + BOOST_CHECK(TmpL == (HalfL >> (i - 1))); + } + BOOST_CHECK(arith_uint256(0xbedc77e27940a7ULL) + 0xee8d836fce66fbULL == + arith_uint256(0xbedc77e27940a7ULL + 0xee8d836fce66fbULL)); + TmpL = arith_uint256(0xbedc77e27940a7ULL); + TmpL += 0xee8d836fce66fbULL; + BOOST_CHECK(TmpL == arith_uint256(0xbedc77e27940a7ULL + 0xee8d836fce66fbULL)); + TmpL -= 0xee8d836fce66fbULL; + BOOST_CHECK(TmpL == 0xbedc77e27940a7ULL); + TmpL = R1L; + BOOST_CHECK(++TmpL == R1L + 1); + + BOOST_CHECK(R1L - (-R2L) == R1L + R2L); + BOOST_CHECK(R1L - (-OneL) == R1L + OneL); + BOOST_CHECK(R1L - OneL == R1L + (-OneL)); + for (unsigned int i = 1; i < 256; ++i) + { + BOOST_CHECK((MaxL >> i) - (-OneL) == (HalfL >> (i - 1))); + BOOST_CHECK((HalfL >> (i - 1)) - OneL == (MaxL >> i)); + TmpL = (HalfL >> (i - 1)); + BOOST_CHECK(TmpL-- == (HalfL >> (i - 1))); + BOOST_CHECK(TmpL == (MaxL >> i)); + TmpL = (HalfL >> (i - 1)); + BOOST_CHECK(--TmpL == (MaxL >> i)); + } + TmpL = R1L; + BOOST_CHECK(--TmpL == R1L - 1); +} + +BOOST_AUTO_TEST_CASE(multiply) +{ + BOOST_CHECK((R1L * R1L).ToString() == "62a38c0486f01e45879d7910a7761bf30d5237e9873f9bff3642a732c4d84f10"); + BOOST_CHECK((R1L * R2L).ToString() == "de37805e9986996cfba76ff6ba51c008df851987d9dd323f0e5de07760529c40"); + BOOST_CHECK((R1L * ZeroL) == ZeroL); + BOOST_CHECK((R1L * OneL) == R1L); + BOOST_CHECK((R1L * MaxL) == -R1L); + BOOST_CHECK((R2L * R1L) == (R1L * R2L)); + BOOST_CHECK((R2L * R2L).ToString() == "ac8c010096767d3cae5005dec28bb2b45a1d85ab7996ccd3e102a650f74ff100"); + BOOST_CHECK((R2L * ZeroL) == ZeroL); + BOOST_CHECK((R2L * OneL) == R2L); + BOOST_CHECK((R2L * MaxL) == -R2L); + + BOOST_CHECK(MaxL * MaxL == OneL); + + BOOST_CHECK((R1L * 0) == 0); + BOOST_CHECK((R1L * 1) == R1L); + BOOST_CHECK((R1L * 3).ToString() == "7759b1c0ed14047f961ad09b20ff83687876a0181a367b813634046f91def7d4"); + BOOST_CHECK((R2L * 0x87654321UL).ToString() == "23f7816e30c4ae2017257b7a0fa64d60402f5234d46e746b61c960d09a26d070"); +} + +BOOST_AUTO_TEST_CASE(divide) +{ + arith_uint256 D1L("AD7133AC1977FA2B7"); + arith_uint256 D2L("ECD751716"); + BOOST_CHECK((R1L / D1L).ToString() == "00000000000000000b8ac01106981635d9ed112290f8895545a7654dde28fb3a"); + BOOST_CHECK((R1L / D2L).ToString() == "000000000873ce8efec5b67150bad3aa8c5fcb70e947586153bf2cec7c37c57a"); + BOOST_CHECK(R1L / OneL == R1L); + BOOST_CHECK(R1L / MaxL == ZeroL); + BOOST_CHECK(MaxL / R1L == 2); + BOOST_CHECK_THROW(R1L / ZeroL, uint_error); + BOOST_CHECK((R2L / D1L).ToString() == "000000000000000013e1665895a1cc981de6d93670105a6b3ec3b73141b3a3c5"); + BOOST_CHECK((R2L / D2L).ToString() == "000000000e8f0abe753bb0afe2e9437ee85d280be60882cf0bd1aaf7fa3cc2c4"); + BOOST_CHECK(R2L / OneL == R2L); + BOOST_CHECK(R2L / MaxL == ZeroL); + BOOST_CHECK(MaxL / R2L == 1); + BOOST_CHECK_THROW(R2L / ZeroL, uint_error); +} + + +bool almostEqual(double d1, double d2) +{ + return fabs(d1 - d2) <= 4 * fabs(d1) * std::numeric_limits::epsilon(); +} + +BOOST_AUTO_TEST_CASE(methods) // GetHex SetHex size() GetLow64 GetSerializeSize, Serialize, Unserialize +{ + BOOST_CHECK(R1L.GetHex() == R1L.ToString()); + BOOST_CHECK(R2L.GetHex() == R2L.ToString()); + BOOST_CHECK(OneL.GetHex() == OneL.ToString()); + BOOST_CHECK(MaxL.GetHex() == MaxL.ToString()); + arith_uint256 TmpL(R1L); + BOOST_CHECK(TmpL == R1L); + TmpL.SetHex(R2L.ToString()); + BOOST_CHECK(TmpL == R2L); + TmpL.SetHex(ZeroL.ToString()); + BOOST_CHECK(TmpL == 0); + TmpL.SetHex(HalfL.ToString()); + BOOST_CHECK(TmpL == HalfL); + + TmpL.SetHex(R1L.ToString()); + BOOST_CHECK(R1L.size() == 32); + BOOST_CHECK(R2L.size() == 32); + BOOST_CHECK(ZeroL.size() == 32); + BOOST_CHECK(MaxL.size() == 32); + BOOST_CHECK(R1L.GetLow64() == R1LLow64); + BOOST_CHECK(HalfL.GetLow64() == 0x0000000000000000ULL); + BOOST_CHECK(OneL.GetLow64() == 0x0000000000000001ULL); + + for (unsigned int i = 0; i < 255; ++i) + { + BOOST_CHECK((OneL << i).getdouble() == ldexp(1.0, i)); + } + BOOST_CHECK(ZeroL.getdouble() == 0.0); + for (int i = 256; i > 53; --i) + BOOST_CHECK(almostEqual((R1L >> (256 - i)).getdouble(), ldexp(R1Ldouble, i))); + uint64_t R1L64part = (R1L >> 192).GetLow64(); + for (int i = 53; i > 0; --i) // doubles can store all integers in {0,...,2^54-1} exactly + { + BOOST_CHECK((R1L >> (256 - i)).getdouble() == (double)(R1L64part >> (64 - i))); + } +} + +BOOST_AUTO_TEST_CASE(bignum_SetCompact) +{ + arith_uint256 num; + bool fNegative; + bool fOverflow; + num.SetCompact(0, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x00123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x01003456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x02000056, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x03000000, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x04000000, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x00923456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x01803456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x02800056, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x03800000, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x04800000, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x01123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000012"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + // Make sure that we don't generate compacts with the 0x00800000 bit set + num = 0x80; + BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000U); + + num.SetCompact(0x01fedcba, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "000000000000000000000000000000000000000000000000000000000000007e"); + BOOST_CHECK_EQUAL(num.GetCompact(true), 0x01fe0000U); + BOOST_CHECK_EQUAL(fNegative, true); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x02123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000001234"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x03123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000123456"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x04123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000012345600"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x04923456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000012345600"); + BOOST_CHECK_EQUAL(num.GetCompact(true), 0x04923456U); + BOOST_CHECK_EQUAL(fNegative, true); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x05009234, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000092340000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x20123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "1234560000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0xff123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, true); +} + + +BOOST_AUTO_TEST_CASE(getmaxcoverage) // some more tests just to get 100% coverage +{ + // ~R1L give a base_uint<256> + BOOST_CHECK((~~R1L >> 10) == (R1L >> 10)); + BOOST_CHECK((~~R1L << 10) == (R1L << 10)); + BOOST_CHECK(!(~~R1L < R1L)); + BOOST_CHECK(~~R1L <= R1L); + BOOST_CHECK(!(~~R1L > R1L)); + BOOST_CHECK(~~R1L >= R1L); + BOOST_CHECK(!(R1L < ~~R1L)); + BOOST_CHECK(R1L <= ~~R1L); + BOOST_CHECK(!(R1L > ~~R1L)); + BOOST_CHECK(R1L >= ~~R1L); + + BOOST_CHECK(~~R1L + R2L == R1L + ~~R2L); + BOOST_CHECK(~~R1L - R2L == R1L - ~~R2L); + BOOST_CHECK(~R1L != R1L); + BOOST_CHECK(R1L != ~R1L); + unsigned char TmpArray[32]; + CHECKBITWISEOPERATOR(~R1, R2, |) + CHECKBITWISEOPERATOR(~R1, R2, ^) + CHECKBITWISEOPERATOR(~R1, R2, &) + CHECKBITWISEOPERATOR(R1, ~R2, |) + CHECKBITWISEOPERATOR(R1, ~R2, ^) + CHECKBITWISEOPERATOR(R1, ~R2, &) +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/bandb_tests.cpp b/src/test/bandb_tests.cpp new file mode 100644 index 00000000..97e5f5a4 --- /dev/null +++ b/src/test/bandb_tests.cpp @@ -0,0 +1,118 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bandb.h" +#include "test/test_bitcoin.h" + +#include + +#include +#include +#include + + +BOOST_FIXTURE_TEST_SUITE(bandb_tests, TestingSetup) + +bool RemoveLocalDatabase(const boost::filesystem::path &path) +{ + try + { + if (boost::filesystem::exists(path)) + { + // if the file already exists, remove it + boost::filesystem::remove(path); + } + + // if we get here, we either successfully deleted the file, or it didn't exist + return true; + } + catch (const std::exception &e) + { + // there was an error deleting the file + return false; + } +} + +BOOST_AUTO_TEST_CASE(bandb_no_database) +{ + // create the CBanDB object + CBanDB db; + + // Ensure local bandlist.dat has been removed + BOOST_CHECK(RemoveLocalDatabase(db.GetDatabasePath())); + + // Try to read non-existent file (this shoudl fail) + banmap_t banset; + BOOST_CHECK(!db.Read(banset)); +} + +BOOST_AUTO_TEST_CASE(bandb_read_write_empty_database) +{ + // create the CBanDB object + CBanDB db; + + // Ensure local bandlist.db has been removed + BOOST_CHECK(RemoveLocalDatabase(db.GetDatabasePath())); + + // Write an empty banset_t to file + banmap_t banset_write; + BOOST_CHECK(db.Write(banset_write)); + + // Read an empty banset_t from file + banmap_t banset_read; + BOOST_CHECK(db.Read(banset_read)); + // And ensure after reading in the banset is still empty + BOOST_CHECK(banset_read.size() == 0); +} + +BOOST_AUTO_TEST_CASE(bandb_read_write_non_empty_database) +{ + // create the CBanDB object + CBanDB db; + + // Ensure local bandlist.db has been removed + BOOST_CHECK(RemoveLocalDatabase(db.GetDatabasePath())); + + // Create sub-nets + CSubNet singleIP("192.168.1.1/32"); + CSubNet subNet("10.168.1.1/24"); + + // Write a non-empty banset_t to file + banmap_t banset_write; + // Add single IP + CBanEntry write1(GetTime()); + write1.banReason = BanReasonNodeMisbehaving; + write1.nBanUntil = GetTime() + 14400; // Ban 4 hours + banset_write[singleIP] = write1; + // Add subnet + CBanEntry write2(GetTime()); + write2.banReason = BanReasonManuallyAdded; + write2.nBanUntil = GetTime() + 28800; // Ban 8 hours + banset_write[subNet] = write2; + // Ensure we can succesfully write to the banlist.dat file + BOOST_CHECK(db.Write(banset_write)); + + // Read a non-empty banset_t from file + banmap_t banset_read; + BOOST_CHECK(db.Read(banset_read)); + // And ensure after reading in the banset contains 2 entries + BOOST_CHECK(banset_read.size() == 2); + + // Ensure entry 1 matches the pre-write entry + CBanEntry *read1 = &banset_read[singleIP]; + BOOST_CHECK(read1 != NULL); + BOOST_CHECK(read1->banReason == write1.banReason); + BOOST_CHECK(read1->nBanUntil == write1.nBanUntil); + BOOST_CHECK(read1->nCreateTime == write1.nCreateTime); + + // Ensure entry 2 matches the pre-write entry + CBanEntry *read2 = &banset_read[subNet]; + BOOST_CHECK(read2 != NULL); + BOOST_CHECK(read2->banReason == write2.banReason); + BOOST_CHECK(read2->nBanUntil == write2.nBanUntil); + BOOST_CHECK(read2->nCreateTime == write2.nCreateTime); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index fdf32859..44b44de0 100644 --- a/src/test/base32_tests.cpp +++ b/src/test/base32_tests.cpp @@ -1,14 +1,21 @@ -#include +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "test/test_bitcoin.h" +#include "utilstrencodings.h" -#include "util.h" +#include -BOOST_AUTO_TEST_SUITE(base32_tests) +BOOST_FIXTURE_TEST_SUITE(base32_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(base32_testvectors) { - static const std::string vstrIn[] = {"","f","fo","foo","foob","fooba","foobar"}; - static const std::string vstrOut[] = {"","my======","mzxq====","mzxw6===","mzxw6yq=","mzxw6ytb","mzxw6ytboi======"}; - for (unsigned int i=0; i -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_writer_template.h" -#include "json/json_spirit_utils.h" +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "base58.h" + +#include "data/base58_encode_decode.json.h" +#include "data/base58_keys_invalid.json.h" +#include "data/base58_keys_valid.json.h" + +#include "key.h" +#include "script/script.h" +#include "test/test_bitcoin.h" +#include "uint256.h" #include "util.h" +#include "utilstrencodings.h" -using namespace json_spirit; -extern Array read_json(const std::string& filename); +#include +#include -BOOST_AUTO_TEST_SUITE(base58_tests) +#include + +extern UniValue read_json(const std::string &jsondata); + +BOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup) // Goal: test low-level base58 encoding functionality BOOST_AUTO_TEST_CASE(base58_EncodeBase58) { - Array tests = read_json("base58_encode_decode.json"); - - for (auto& tv: tests) + UniValue tests = read_json(std::string( + json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode))); + for (unsigned int idx = 0; idx < tests.size(); idx++) { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + UniValue test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 2) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -27,22 +41,21 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58) } std::vector sourcedata = ParseHex(test[0].get_str()); std::string base58string = test[1].get_str(); - BOOST_CHECK_MESSAGE( - EncodeBase58(&sourcedata[0], &sourcedata[sourcedata.size()]) == base58string, - strTest); + BOOST_CHECK_MESSAGE(EncodeBase58(begin_ptr(sourcedata), end_ptr(sourcedata)) == base58string, strTest); } } // Goal: test low-level base58 decoding functionality BOOST_AUTO_TEST_CASE(base58_DecodeBase58) { - Array tests = read_json("base58_encode_decode.json"); + UniValue tests = read_json(std::string( + json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode))); std::vector result; - for (auto& tv: tests) + for (unsigned int idx = 0; idx < tests.size(); idx++) { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + UniValue test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 2) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -51,10 +64,17 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58) std::vector expected = ParseHex(test[0].get_str()); std::string base58string = test[1].get_str(); BOOST_CHECK_MESSAGE(DecodeBase58(base58string, result), strTest); - BOOST_CHECK_MESSAGE(result.size() == expected.size() && std::equal(result.begin(), result.end(), expected.begin()), strTest); + BOOST_CHECK_MESSAGE( + result.size() == expected.size() && std::equal(result.begin(), result.end(), expected.begin()), strTest); } BOOST_CHECK(!DecodeBase58("invalid", result)); + + // check that DecodeBase58 skips whitespace, but still fails with unexpected non-whitespace at the end. + BOOST_CHECK(!DecodeBase58(" \t\n\v\f\r skip \r\f\v\n\t a", result)); + BOOST_CHECK(DecodeBase58(" \t\n\v\f\r skip \r\f\v\n\t ", result)); + std::vector expected = ParseHex("971a55"); + BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); } // Visitor to check address type @@ -62,20 +82,12 @@ class TestAddrTypeVisitor : public boost::static_visitor { private: std::string exp_addrType; + public: - TestAddrTypeVisitor(const std::string &exp_addrType) : exp_addrType(exp_addrType) { } - bool operator()(const CKeyID &id) const - { - return (exp_addrType == "pubkey"); - } - bool operator()(const CScriptID &id) const - { - return (exp_addrType == "script"); - } - bool operator()(const CNoDestination &no) const - { - return (exp_addrType == "none"); - } + TestAddrTypeVisitor(const std::string &exp_addrType) : exp_addrType(exp_addrType) {} + bool operator()(const CKeyID &id) const { return (exp_addrType == "pubkey"); } + bool operator()(const CScriptID &id) const { return (exp_addrType == "script"); } + bool operator()(const CNoDestination &no) const { return (exp_addrType == "none"); } }; // Visitor to check address payload @@ -83,8 +95,9 @@ class TestPayloadVisitor : public boost::static_visitor { private: std::vector exp_payload; + public: - TestPayloadVisitor(std::vector &exp_payload) : exp_payload(exp_payload) { } + TestPayloadVisitor(std::vector &exp_payload) : exp_payload(exp_payload) {} bool operator()(const CKeyID &id) const { uint160 exp_key(exp_payload); @@ -95,26 +108,23 @@ class TestPayloadVisitor : public boost::static_visitor uint160 exp_key(exp_payload); return exp_key == id; } - bool operator()(const CNoDestination &no) const - { - return exp_payload.size() == 0; - } + bool operator()(const CNoDestination &no) const { return exp_payload.size() == 0; } }; // Goal: check that parsed keys match test payload BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) { - Array tests = read_json("base58_keys_valid.json"); + UniValue tests = read_json(std::string( + json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); std::vector result; CBitcoinSecret secret; CBitcoinAddress addr; - // Save global state - bool fTestNet_stored = fTestNet; + SelectParams(CBaseChainParams::MAIN); - for (auto& tv: tests) + for (unsigned int idx = 0; idx < tests.size(); idx++) { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + UniValue test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 3) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -122,21 +132,25 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) } std::string exp_base58string = test[0].get_str(); std::vector exp_payload = ParseHex(test[1].get_str()); - const Object &metadata = test[2].get_obj(); + const UniValue &metadata = test[2].get_obj(); bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); bool isTestnet = find_value(metadata, "isTestnet").get_bool(); - fTestNet = isTestnet; // Override testnet flag - if(isPrivkey) + if (isTestnet) + SelectParams(CBaseChainParams::TESTNET); + else + SelectParams(CBaseChainParams::MAIN); + if (isPrivkey) { bool isCompressed = find_value(metadata, "isCompressed").get_bool(); // Must be valid private key // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not! - BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest); + BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:" + strTest); BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest); - bool fCompressedOut = false; - CSecret privkey = secret.GetSecret(fCompressedOut); - BOOST_CHECK_MESSAGE(fCompressedOut == isCompressed, "compressed mismatch:" + strTest); - BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest); + CKey privkey = secret.GetKey(); + BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest); + BOOST_CHECK_MESSAGE( + privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), + "key mismatch:" + strTest); // Private key must be invalid public key addr.SetString(exp_base58string); @@ -150,29 +164,27 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest); BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest); CTxDestination dest = addr.Get(); - BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest); + BOOST_CHECK_MESSAGE( + boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest); // Public key must be invalid private key secret.SetString(exp_base58string); BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest); } } - // Restore global state - fTestNet = fTestNet_stored; } // Goal: check that generated keys match test vectors BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) { - Array tests = read_json("base58_keys_valid.json"); + UniValue tests = read_json(std::string( + json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); std::vector result; - // Save global state - bool fTestNet_stored = fTestNet; - for (auto& tv: tests) + for (unsigned int idx = 0; idx < tests.size(); idx++) { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + UniValue test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 3) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -180,30 +192,36 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) } std::string exp_base58string = test[0].get_str(); std::vector exp_payload = ParseHex(test[1].get_str()); - const Object &metadata = test[2].get_obj(); + const UniValue &metadata = test[2].get_obj(); bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); bool isTestnet = find_value(metadata, "isTestnet").get_bool(); - fTestNet = isTestnet; // Override testnet flag - if(isPrivkey) + if (isTestnet) + SelectParams(CBaseChainParams::TESTNET); + else + SelectParams(CBaseChainParams::MAIN); + if (isPrivkey) { bool isCompressed = find_value(metadata, "isCompressed").get_bool(); + CKey key; + key.Set(exp_payload.begin(), exp_payload.end(), isCompressed); + assert(key.IsValid()); CBitcoinSecret secret; - secret.SetSecret(CSecret(exp_payload.begin(), exp_payload.end()), isCompressed); + secret.SetKey(key); BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest); } else { std::string exp_addrType = find_value(metadata, "addrType").get_str(); CTxDestination dest; - if(exp_addrType == "pubkey") + if (exp_addrType == "pubkey") { dest = CKeyID(uint160(exp_payload)); } - else if(exp_addrType == "script") + else if (exp_addrType == "script") { dest = CScriptID(uint160(exp_payload)); } - else if(exp_addrType == "none") + else if (exp_addrType == "none") { dest = CNoDestination(); } @@ -213,7 +231,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) continue; } CBitcoinAddress addrOut; - BOOST_CHECK_MESSAGE(boost::apply_visitor(CBitcoinAddressVisitor(&addrOut), dest), "encode dest: " + strTest); + BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest); BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest); } } @@ -221,24 +239,25 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) // Visiting a CNoDestination must fail CBitcoinAddress dummyAddr; CTxDestination nodest = CNoDestination(); - BOOST_CHECK(!boost::apply_visitor(CBitcoinAddressVisitor(&dummyAddr), nodest)); + BOOST_CHECK(!dummyAddr.Set(nodest)); - // Restore global state - fTestNet = fTestNet_stored; + SelectParams(CBaseChainParams::MAIN); } // Goal: check that base58 parsing code is robust against a variety of corrupted data BOOST_AUTO_TEST_CASE(base58_keys_invalid) { - Array tests = read_json("base58_keys_invalid.json"); // Negative testcases + // Negative testcases + UniValue tests = read_json(std::string( + json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); std::vector result; CBitcoinSecret secret; CBitcoinAddress addr; - for (auto& tv: tests) + for (unsigned int idx = 0; idx < tests.size(); idx++) { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + UniValue test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 1) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -256,4 +275,3 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid) BOOST_AUTO_TEST_SUITE_END() - diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp index c5a053e2..cc4cb7d2 100644 --- a/src/test/base64_tests.cpp +++ b/src/test/base64_tests.cpp @@ -1,16 +1,20 @@ -#include +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "test/test_bitcoin.h" +#include "utilstrencodings.h" -#include "main.h" -#include "wallet.h" -#include "util.h" +#include -BOOST_AUTO_TEST_SUITE(base64_tests) +BOOST_FIXTURE_TEST_SUITE(base64_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(base64_testvectors) { - static const std::string vstrIn[] = {"","f","fo","foo","foob","fooba","foobar"}; - static const std::string vstrOut[] = {"","Zg==","Zm8=","Zm9v","Zm9vYg==","Zm9vYmE=","Zm9vYmFy"}; - for (unsigned int i=0; i + +#include "base58.h" +#include "key.h" +#include "test/test_bitcoin.h" +#include "uint256.h" +#include "util.h" +#include "utilstrencodings.h" + +#include +#include + +struct TestDerivation +{ + std::string pub; + std::string prv; + unsigned int nChild; +}; + +struct TestVector +{ + std::string strHexMaster; + std::vector vDerive; + + TestVector(std::string strHexMasterIn) : strHexMaster(strHexMasterIn) {} + TestVector &operator()(std::string pub, std::string prv, unsigned int nChild) + { + vDerive.push_back(TestDerivation()); + TestDerivation &der = vDerive.back(); + der.pub = pub; + der.prv = prv; + der.nChild = nChild; + return *this; + } +}; + +TestVector test1 = TestVector("000102030405060708090a0b0c0d0e0f")( + "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8", + "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", + 0x80000000)( + "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw", + "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7", + 1)( + "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ", + "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs", + 0x80000002)( + "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5", + "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM", + 2)( + "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV", + "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334", + 1000000000)( + "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy", + "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76", + 0); + +TestVector test2 = TestVector("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e" + "7b7875726f6c696663605d5a5754514e4b484542")( + "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB", + "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U", + 0)( + "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH", + "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt", + 0xFFFFFFFF)( + "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a", + "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9", + 1)( + "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon", + "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef", + 0xFFFFFFFE)( + "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL", + "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc", + 2)( + "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt", + "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j", + 0); + +void RunTest(const TestVector &test) +{ + std::vector seed = ParseHex(test.strHexMaster); + CExtKey key; + CExtPubKey pubkey; + key.SetMaster(&seed[0], seed.size()); + pubkey = key.Neuter(); + BOOST_FOREACH (const TestDerivation &derive, test.vDerive) + { + unsigned char data[74]; + key.Encode(data); + pubkey.Encode(data); + + // Test private key + CBitcoinExtKey b58key; + b58key.SetKey(key); + BOOST_CHECK(b58key.ToString() == derive.prv); + + CBitcoinExtKey b58keyDecodeCheck(derive.prv); + CExtKey checkKey = b58keyDecodeCheck.GetKey(); + assert(checkKey == key); // ensure a base58 decoded key also matches + + // Test public key + CBitcoinExtPubKey b58pubkey; + b58pubkey.SetKey(pubkey); + BOOST_CHECK(b58pubkey.ToString() == derive.pub); + + CBitcoinExtPubKey b58PubkeyDecodeCheck(derive.pub); + CExtPubKey checkPubKey = b58PubkeyDecodeCheck.GetKey(); + assert(checkPubKey == pubkey); // ensure a base58 decoded pubkey also matches + + // Derive new keys + CExtKey keyNew; + BOOST_CHECK(key.Derive(keyNew, derive.nChild)); + CExtPubKey pubkeyNew = keyNew.Neuter(); + if (!(derive.nChild & 0x80000000)) + { + // Compare with public derivation + CExtPubKey pubkeyNew2; + BOOST_CHECK(pubkey.Derive(pubkeyNew2, derive.nChild)); + BOOST_CHECK(pubkeyNew == pubkeyNew2); + } + key = keyNew; + pubkey = pubkeyNew; + } +} + +BOOST_FIXTURE_TEST_SUITE(bip32_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(bip32_test1) { RunTest(test1); } +BOOST_AUTO_TEST_CASE(bip32_test2) { RunTest(test2); } +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py new file mode 100644 index 00000000..20afb16a --- /dev/null +++ b/src/test/bitcoin-util-test.py @@ -0,0 +1,13 @@ +#!/usr/bin/python +# Copyright 2014 BitPay, Inc. +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import os +import bctest +import buildenv + +if __name__ == '__main__': + bctest.bctester(os.environ["srcdir"] + "/test/data", + "bitcoin-util-test.json",buildenv) + diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp new file mode 100644 index 00000000..e85f1d9f --- /dev/null +++ b/src/test/bloom_tests.cpp @@ -0,0 +1,1003 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bloom.h" + +#include "base58.h" +#include "clientversion.h" +#include "key.h" +#include "merkleblock.h" +#include "random.h" +#include "serialize.h" +#include "streams.h" +#include "test/test_bitcoin.h" +#include "uint256.h" +#include "util.h" +#include "utilstrencodings.h" + +#include + +#include +#include + +using namespace std; + +BOOST_FIXTURE_TEST_SUITE(bloom_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize) +{ + CBloomFilter filter(3, 0.01, 0, BLOOM_UPDATE_ALL); + + filter.insert(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")); + BOOST_CHECK_MESSAGE(filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), + "BloomFilter doesn't contain just-inserted object!"); + // One bit different in first byte + BOOST_CHECK_MESSAGE(!filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), + "BloomFilter contains something it shouldn't!"); + + filter.insert(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")); + BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), + "BloomFilter doesn't contain just-inserted object (2)!"); + + filter.insert(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")); + BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), + "BloomFilter doesn't contain just-inserted object (3)!"); + + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << filter; + + vector vch = ParseHex("03614e9b050000000000000001"); + vector expected(vch.size()); + + for (unsigned int i = 0; i < vch.size(); i++) + expected[i] = (char)vch[i]; + + BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end()); + + BOOST_CHECK_MESSAGE(filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), + "BloomFilter doesn't contain just-inserted object!"); + filter.clear(); + BOOST_CHECK_MESSAGE( + !filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter should be empty!"); +} + +BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) +{ + // Same test as bloom_create_insert_serialize, but we add a nTweak of 100 + CBloomFilter filter(3, 0.01, 2147483649UL, BLOOM_UPDATE_ALL); + + filter.insert(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")); + BOOST_CHECK_MESSAGE(filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), + "BloomFilter doesn't contain just-inserted object!"); + // One bit different in first byte + BOOST_CHECK_MESSAGE(!filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), + "BloomFilter contains something it shouldn't!"); + + filter.insert(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")); + BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), + "BloomFilter doesn't contain just-inserted object (2)!"); + + filter.insert(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")); + BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), + "BloomFilter doesn't contain just-inserted object (3)!"); + + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << filter; + + vector vch = ParseHex("03ce4299050000000100008001"); + vector expected(vch.size()); + + for (unsigned int i = 0; i < vch.size(); i++) + expected[i] = (char)vch[i]; + + BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end()); +} + +BOOST_AUTO_TEST_CASE(bloom_create_insert_key) +{ + string strSecret = string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"); + CBitcoinSecret vchSecret; + BOOST_CHECK(vchSecret.SetString(strSecret)); + + CKey key = vchSecret.GetKey(); + CPubKey pubkey = key.GetPubKey(); + vector vchPubKey(pubkey.begin(), pubkey.end()); + + CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL); + filter.insert(vchPubKey); + uint160 hash = pubkey.GetID(); + filter.insert(vector(hash.begin(), hash.end())); + + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << filter; + + vector vch = ParseHex("038fc16b080000000000000001"); + vector expected(vch.size()); + + for (unsigned int i = 0; i < vch.size(); i++) + expected[i] = (char)vch[i]; + + BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end()); +} + +BOOST_AUTO_TEST_CASE(bloom_match) +{ + // Random real transaction (b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b) + CTransaction tx; + CDataStream stream( + ParseHex("01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e88607d722c190000000008b4830450220070aca4" + "4506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b864" + "3ac4cb7cb3c462aced7f14711a0141046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eee" + "f87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffffffff021bff3d11000000001976a91404943fdd" + "508053c75000106d3bc6e2754dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d9032a7b9d64fa4318" + "8ac00000000"), + SER_DISK, CLIENT_VERSION); + stream >> tx; + + // and one which spends it (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) + unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, + 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, + 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, + 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, + 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, + 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, + 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, + 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, + 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, + 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, + 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, + 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, + 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, + 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; + vector vch(ch, ch + sizeof(ch) - 1); + CDataStream spendStream(vch, SER_DISK, CLIENT_VERSION); + CTransaction spendingTx; + spendStream >> spendingTx; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(uint256S("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b")); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match tx hash"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + // byte-reversed tx hash + filter.insert(ParseHex("6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4")); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized tx hash"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(ParseHex("30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d" + "43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a01")); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match input signature"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(ParseHex("046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a845" + "65f80fa6c547957b7700ff4dfbdefe76036c339")); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match input pub key"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(ParseHex("04943fdd508053c75000106d3bc6e2754dbcff19")); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address"); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(spendingTx), "Simple Bloom filter didn't add output"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(ParseHex("a266436d2965547608b9e15d9032a7b9d64fa431")); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(COutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0)); + BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match COutPoint"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + COutPoint prevOutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0); + { + vector data(32 + sizeof(unsigned int)); + memcpy(&data[0], prevOutPoint.hash.begin(), 32); + memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int)); + filter.insert(data); + } + BOOST_CHECK_MESSAGE( + filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized COutPoint"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(uint256S("00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436")); + BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random tx hash"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(ParseHex("0000006d2965547608b9e15d9032a7b9d64fa431")); + BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random address"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(COutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 1)); + BOOST_CHECK_MESSAGE( + !filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about"); + + filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + filter.insert(COutPoint(uint256S("0x000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0)); + BOOST_CHECK_MESSAGE( + !filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about"); +} + +BOOST_AUTO_TEST_CASE(merkle_block_1) +{ + // Random real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af) + // With 9 txes + CBlock block; + CDataStream stream( + ParseHex( + "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c" + "3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000" + "000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc" + "8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00" + "000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab2" + "4889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c31" + "1b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac00" + "0000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268" + "ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc" + "597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e5" + "71fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a" + "0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac00000000010000" + "0002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e" + "5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe6" + "7512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf97584" + "5c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035d" + "defb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14" + "a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14c" + "a4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043" + "410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9" + "d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5" + "c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e" + "5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d7" + "89904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c0000000000" + "1976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb" + "042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a" + "4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987da" + "d92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3" + "cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a91455056148" + "59643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00" + "000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc" + "2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f" + "7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c6" + "9b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa" + "4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702" + "200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f" + "388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acf" + "cab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48" + "cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805" + "c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1" + "d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd20000" + "00008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae" + "2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07" + "d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc65" + "14edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558" + "165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3" + "a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8eb" + "bb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166" + "d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229ce" + "fc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b6" + "3f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a3316" + "1dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688" + "ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a905" + "9cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c35306" + "9e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c" + "79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce30" + "12e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c0000" + "0000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"), + SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + // Match the last transaction + filter.insert(uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); + pair pair = merkleBlock.vMatchedTxn[0]; + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == + uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8); + + vector vMatched; + vector vIndex; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); + + // Also match the 8th transaction + filter.insert(uint256S("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053")); + merkleBlock = CMerkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 2); + + BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair); + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == + uint256S("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 7); + + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); +} + +BOOST_AUTO_TEST_CASE(merkle_block_2) +{ + // Random real block (000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6) + // With 4 txes + CBlock block; + CDataStream stream( + ParseHex("0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f605021124991" + "9b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a441040100000001000000000000000000000000000000" + "0000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a04" + "1d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2" + "fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d283" + "50000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54" + "bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be" + "385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683" + "bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000" + "000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111" + "b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c1" + "6202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001" + "000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484" + "157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2" + "e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c202801000" + "0004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59" + "e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce0" + "8dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8" + "e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e39" + "29a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d9639" + "14bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac53" + "7eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffff" + "ffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588" + "d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b" + "2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2" + "e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f00000000" + "4341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37" + "b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"), + SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + // Match the first transaction + filter.insert(uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); + pair pair = merkleBlock.vMatchedTxn[0]; + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == + uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); + + vector vMatched; + vector vIndex; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); + + // Match an output from the second transaction (the pubkey for address 1DZTzaBHUDM7T3QvUKBz4qXMRpkg8jsfB5) + // This should match the third transaction because it spends the output matched + // It also matches the fourth transaction, which spends to the pubkey again + filter.insert(ParseHex("044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a019" + "28f8dd2c875a390f67c1f6c94cfc617c0ea45af")); + + merkleBlock = CMerkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 4); + + BOOST_CHECK(pair == merkleBlock.vMatchedTxn[0]); + + BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == + uint256S("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f")); + BOOST_CHECK(merkleBlock.vMatchedTxn[1].first == 1); + + BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == + uint256S("0x6b0f8a73a56c04b519f1883e8aafda643ba61a30bd1439969df21bea5f4e27e2")); + BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 2); + + BOOST_CHECK(merkleBlock.vMatchedTxn[3].second == + uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23")); + BOOST_CHECK(merkleBlock.vMatchedTxn[3].first == 3); + + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); +} + +BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none) +{ + // Random real block (000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6) + // With 4 txes + CBlock block; + CDataStream stream( + ParseHex("0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f605021124991" + "9b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a441040100000001000000000000000000000000000000" + "0000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a04" + "1d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2" + "fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d283" + "50000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54" + "bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be" + "385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683" + "bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000" + "000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111" + "b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c1" + "6202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001" + "000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484" + "157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2" + "e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c202801000" + "0004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59" + "e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce0" + "8dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8" + "e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e39" + "29a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d9639" + "14bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac53" + "7eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffff" + "ffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588" + "d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b" + "2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2" + "e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f00000000" + "4341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37" + "b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"), + SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_NONE); + // Match the first transaction + filter.insert(uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); + pair pair = merkleBlock.vMatchedTxn[0]; + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == + uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); + + vector vMatched; + vector vIndex; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); + + // Match an output from the second transaction (the pubkey for address 1DZTzaBHUDM7T3QvUKBz4qXMRpkg8jsfB5) + // This should not match the third transaction though it spends the output matched + // It will match the fourth transaction, which has another pay-to-pubkey output to the same address + filter.insert(ParseHex("044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a019" + "28f8dd2c875a390f67c1f6c94cfc617c0ea45af")); + + merkleBlock = CMerkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 3); + + BOOST_CHECK(pair == merkleBlock.vMatchedTxn[0]); + + BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == + uint256S("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f")); + BOOST_CHECK(merkleBlock.vMatchedTxn[1].first == 1); + + BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == + uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23")); + BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 3); + + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); +} + +BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize) +{ + // Random real block (000000000000dab0130bbcc991d3d7ae6b81aa6f50a798888dfe62337458dc45) + // With one tx + CBlock block; + CDataStream stream( + ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d" + "3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d63010100000001000000000000000000000000000000" + "0000000000000000000000000000000000ffffffff08044c86041b020a02ffffffff0100f2052a01000000434104ecd3229b0" + "571c3be876feaac0442a9f13c5a572742927af1dc623353ecf8c202225f64868137a18cdd85cbbb4c74fbccfd4f49639cf1bd" + "c94a5672bb15ad5d4cac00000000"), + SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + // Match the only transaction + filter.insert(uint256S("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == + uint256S("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); + + vector vMatched; + vector vIndex; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); + + CDataStream merkleStream(SER_NETWORK, PROTOCOL_VERSION); + merkleStream << merkleBlock; + + vector vch = + ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d" + "3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3fe" + "be7c770fdcc96b2c3ff60abe184f19630101"); + vector expected(vch.size()); + + for (unsigned int i = 0; i < vch.size(); i++) + expected[i] = (char)vch[i]; + + BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), merkleStream.begin(), merkleStream.end()); +} + +BOOST_AUTO_TEST_CASE(merkle_block_4) +{ + // Random real block (000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4) + // With 7 txes + CBlock block; + CDataStream stream( + ParseHex( + "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f09" + "3bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000" + "000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241b" + "cab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac00" + "0000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e83" + "4b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b" + "3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065" + "cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2" + "e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82" + "c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29" + "b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4af" + "ae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202b" + "db79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415" + "c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c1000000" + "0049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f118" + "7779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf7" + "94376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a0068174344700000000" + "8b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89" + "978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f" + "4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f2" + "48e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d" + "5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b" + "4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec" + "95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d17145" + "51663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46" + "fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ff" + "b5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f99" + "9b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d1" + "7b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9" + "ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817" + "a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10" + "545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284" + "e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f" + "464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d" + "9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976" + "a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189" + "fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266" + "c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e9" + "5a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffff" + "ffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d0434" + "1d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a" + "452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e32" + "5d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fe" + "e61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551d" + "d7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c476" + "88127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141" + "049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba3400" + "68c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac0000" + "0000"), + SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); + // Match the last transaction + filter.insert(uint256S("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); + pair pair = merkleBlock.vMatchedTxn[0]; + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == + uint256S("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6); + + vector vMatched; + vector vIndex; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); + + // Also match the 4th transaction + filter.insert(uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041")); + merkleBlock = CMerkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 2); + + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == + uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 3); + + BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair); + + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); + BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); + for (unsigned int i = 0; i < vMatched.size(); i++) + BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); +} + +BOOST_AUTO_TEST_CASE(merkle_block_4_test_p2pubkey_only) +{ + // Random real block (000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4) + // With 7 txes + CBlock block; + CDataStream stream( + ParseHex( + "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f09" + "3bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000" + "000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241b" + "cab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac00" + "0000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e83" + "4b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b" + "3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065" + "cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2" + "e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82" + "c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29" + "b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4af" + "ae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202b" + "db79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415" + "c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c1000000" + "0049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f118" + "7779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf7" + "94376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a0068174344700000000" + "8b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89" + "978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f" + "4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f2" + "48e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d" + "5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b" + "4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec" + "95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d17145" + "51663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46" + "fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ff" + "b5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f99" + "9b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d1" + "7b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9" + "ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817" + "a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10" + "545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284" + "e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f" + "464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d" + "9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976" + "a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189" + "fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266" + "c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e9" + "5a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffff" + "ffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d0434" + "1d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a" + "452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e32" + "5d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fe" + "e61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551d" + "d7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c476" + "88127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141" + "049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba3400" + "68c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac0000" + "0000"), + SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_P2PUBKEY_ONLY); + // Match the generation pubkey + filter.insert(ParseHex("04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d8111" + "3c3807420ce13ad1357231a2252247d97a46a91")); + // ...and the output address of the 4th transaction + filter.insert(ParseHex("b6efd80d99179f4f4ff6f4dd0a007d018c385d21")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + // We should match the generation outpoint + BOOST_CHECK( + filter.contains(COutPoint(uint256S("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0))); + // ... but not the 4th transaction's output (its not pay-2-pubkey) + BOOST_CHECK( + !filter.contains(COutPoint(uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0))); +} + +BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none) +{ + // Random real block (000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4) + // With 7 txes + CBlock block; + CDataStream stream( + ParseHex( + "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f09" + "3bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000" + "000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241b" + "cab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac00" + "0000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e83" + "4b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b" + "3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065" + "cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2" + "e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82" + "c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29" + "b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4af" + "ae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202b" + "db79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415" + "c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c1000000" + "0049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f118" + "7779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf7" + "94376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a0068174344700000000" + "8b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89" + "978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f" + "4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f2" + "48e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d" + "5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b" + "4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec" + "95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d17145" + "51663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46" + "fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ff" + "b5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f99" + "9b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d1" + "7b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9" + "ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817" + "a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10" + "545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284" + "e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f" + "464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d" + "9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976" + "a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189" + "fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266" + "c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e9" + "5a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffff" + "ffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d0434" + "1d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a" + "452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e32" + "5d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fe" + "e61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551d" + "d7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c476" + "88127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141" + "049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba3400" + "68c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac0000" + "0000"), + SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_NONE); + // Match the generation pubkey + filter.insert(ParseHex("04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d8111" + "3c3807420ce13ad1357231a2252247d97a46a91")); + // ...and the output address of the 4th transaction + filter.insert(ParseHex("b6efd80d99179f4f4ff6f4dd0a007d018c385d21")); + + CMerkleBlock merkleBlock(block, filter); + BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); + + // We shouldn't match any outpoints (UPDATE_NONE) + BOOST_CHECK( + !filter.contains(COutPoint(uint256S("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0))); + BOOST_CHECK( + !filter.contains(COutPoint(uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0))); +} + +static std::vector RandomData() +{ + uint256 r = GetRandHash(); + return std::vector(r.begin(), r.end()); +} + +BOOST_AUTO_TEST_CASE(rolling_bloom) +{ + // last-100-entry, 1% false positive: + CRollingBloomFilter rb1(100, 0.01); + + // Overfill: + static const int DATASIZE = 399; + std::vector data[DATASIZE]; + for (int i = 0; i < DATASIZE; i++) + { + data[i] = RandomData(); + rb1.insert(data[i]); + } + // Last 100 guaranteed to be remembered: + for (int i = 299; i < DATASIZE; i++) + { + BOOST_CHECK(rb1.contains(data[i])); + } + + // false positive rate is 1%, so we should get about 100 hits if + // testing 10,000 random keys. We get worst-case false positive + // behavior when the filter is as full as possible, which is + // when we've inserted one minus an integer multiple of nElement*2. + unsigned int nHits = 0; + for (int i = 0; i < 10000; i++) + { + if (rb1.contains(RandomData())) + ++nHits; + } + // Run test_bitcoin with --log_level=message to see BOOST_TEST_MESSAGEs: + BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~100 expected)"); + + // Insanely unlikely to get a fp count outside this range: + BOOST_CHECK(nHits > 25); + BOOST_CHECK(nHits < 175); + + BOOST_CHECK(rb1.contains(data[DATASIZE - 1])); + rb1.reset(); + BOOST_CHECK(!rb1.contains(data[DATASIZE - 1])); + + // Now roll through data, make sure last 100 entries + // are always remembered: + for (int i = 0; i < DATASIZE; i++) + { + if (i >= 100) + BOOST_CHECK(rb1.contains(data[i - 100])); + rb1.insert(data[i]); + } + + // Insert 999 more random entries: + for (int i = 0; i < 999; i++) + { + rb1.insert(RandomData()); + } + // Sanity check to make sure the filter isn't just filling up: + nHits = 0; + for (int i = 0; i < DATASIZE; i++) + { + if (rb1.contains(data[i])) + ++nHits; + } + // Expect about 5 false positives, more than 100 means + // something is definitely broken. + BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~5 expected)"); + BOOST_CHECK(nHits < 100); + + // last-1000-entry, 0.01% false positive: + CRollingBloomFilter rb2(1000, 0.001); + for (int i = 0; i < DATASIZE; i++) + { + rb2.insert(data[i]); + } + // ... room for all of them: + for (int i = 0; i < DATASIZE; i++) + { + BOOST_CHECK(rb2.contains(data[i])); + } +} + +BOOST_AUTO_TEST_CASE(bloom_full_and_size_tests) +{ + { + // FP rate of 1.0 will create an empty, zero-element bloom filter + CBloomFilter filter(1, 1.0, 0, BLOOM_UPDATE_ALL); + BOOST_CHECK(filter.getFull()); + filter.insert(ParseHex("00")); + } + + { + // a filter with good parameters should be non-full upon construction + CBloomFilter filter(8, 0.01, 0, BLOOM_UPDATE_ALL); + BOOST_CHECK(!filter.getFull()); + } + + { + // constructing bloom filters without any empty elements should work + // and yield non-full filters as nElements will be set to 1 + CBloomFilter filter(0, 0.01, 0, BLOOM_UPDATE_ALL); + BOOST_CHECK(!filter.getFull()); + } + + { + // default empty filter is full + CBloomFilter filter; + BOOST_CHECK(filter.getFull()); + } + + { + // deserialization of empty filter should indicate it is full + // (test for implicit UpdateEmptyFull) + CBloomFilter filter; + CDataStream stream(ParseHex("00000000000000000000"), SER_NETWORK, PROTOCOL_VERSION); + stream >> filter; + BOOST_CHECK(filter.getFull()); + BOOST_CHECK(filter.IsWithinSizeConstraints()); + } + + { + // deserialization of one-element empty filter should be non-full + // (test for implicit UpdateEmptyFull) + CBloomFilter filter; + CDataStream stream(ParseHex("0100000000000000000000"), SER_NETWORK, PROTOCOL_VERSION); + stream >> filter; + BOOST_CHECK(!filter.getFull()); + BOOST_CHECK(filter.IsWithinSizeConstraints()); + } + + { + // deserialization of one-element full filter should indicate fullness + // (test for implicit UpdateEmptyFull) + CBloomFilter filter; + CDataStream stream(ParseHex("01ff000000000000000000"), SER_NETWORK, PROTOCOL_VERSION); + stream >> filter; + BOOST_CHECK(filter.getFull()); + BOOST_CHECK(filter.IsWithinSizeConstraints()); + } + { + // deserialization of large empty filter + // (test for implicit UpdateEmptyFull, size constraint check) + CBloomFilter filter; + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + + vector vch(1U << 20); // too large filter + stream << vch; + stream << 0U; // nHashFuncs + stream << 0U; // nTweak + stream << (unsigned char)0; // nFlags + + stream >> filter; + BOOST_CHECK(!filter.getFull()); + BOOST_CHECK(!filter.IsWithinSizeConstraints()); + } + + { + // deserialization of large full filter + // (test for implicit UpdateEmptyFull, size constraint check) + CBloomFilter filter; + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + + vector vch(1U << 20, 0xff); // too large filter + stream << vch; + stream << 0U; // nHashFuncs + stream << 0U; // nTweak + stream << (unsigned char)0; // nFlags + + + stream >> filter; + BOOST_CHECK(filter.getFull()); + BOOST_CHECK(!filter.IsWithinSizeConstraints()); + } + + { + // deserialization of empty filter with too many hash functions + // (to check size constraint check) + CBloomFilter filter; + CDataStream stream(ParseHex("0000ffffff0000000000"), SER_NETWORK, PROTOCOL_VERSION); + stream >> filter; + BOOST_CHECK(!filter.IsWithinSizeConstraints()); + } + + { + // a rolling bloom filter can be constructed with much larger size than a regular one + CRollingBloomFilter rollbloom(120000, 0.000001); + BOOST_CHECK(rollbloom.vDataTotalSize() > 800000); + } + + { + // a regular one, not so much + CBloomFilter filter(120000, 0.000001, 0, 0); + BOOST_CHECK(filter.vDataSize() < 50000); + } +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/bswap_tests.cpp b/src/test/bswap_tests.cpp new file mode 100644 index 00000000..5089a28c --- /dev/null +++ b/src/test/bswap_tests.cpp @@ -0,0 +1,26 @@ +// 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 "compat/byteswap.h" +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(bswap_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(bswap_tests) +{ + // Sibling in bitcoin/src/qt/test/compattests.cpp + uint16_t u1 = 0x1234; + uint32_t u2 = 0x56789abc; + uint64_t u3 = 0xdef0123456789abc; + uint16_t e1 = 0x3412; + uint32_t e2 = 0xbc9a7856; + uint64_t e3 = 0xbc9a78563412f0de; + BOOST_CHECK(bswap_16(u1) == e1); + BOOST_CHECK(bswap_32(u2) == e2); + BOOST_CHECK(bswap_64(u3) == e3); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/buildenv.py.in b/src/test/buildenv.py.in new file mode 100644 index 00000000..1618bdeb --- /dev/null +++ b/src/test/buildenv.py.in @@ -0,0 +1,2 @@ +#!/usr/bin/python +exeext="@EXEEXT@" diff --git a/src/test/buip055_test.cpp b/src/test/buip055_test.cpp new file mode 100644 index 00000000..b62ce3a1 --- /dev/null +++ b/src/test/buip055_test.cpp @@ -0,0 +1,155 @@ +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "data/tx_invalid.json.h" +#include "data/tx_valid.json.h" +#include "test/test_bitcoin.h" + +#include "buip055fork.h" +#include "clientversion.h" +#include "consensus/validation.h" +#include "core_io.h" +#include "key.h" +#include "keystore.h" +#include "main.h" // For CheckTransaction +#include "policy/policy.h" +#include "script/script.h" +#include "script/script_error.h" +#include "script/sign.h" +#include "utilstrencodings.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include + +BOOST_FIXTURE_TEST_SUITE(buip055_tests, BasicTestingSetup) + +// Helper: create two dummy transactions, each with +// two outputs. The first has 11 and 50 CENT outputs +// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs +// paid to a TX_PUBKEYHASH. +// +static std::vector SetupDummyInputs(CBasicKeyStore &keystoreRet, CCoinsViewCache &coinsRet) +{ + std::vector dummyTransactions; + dummyTransactions.resize(2); + + // Add some keys to the keystore: + CKey key[4]; + for (int i = 0; i < 4; i++) + { + key[i].MakeNewKey(i % 2); + keystoreRet.AddKey(key[i]); + } + + // Create some dummy input transactions + int nHeight = 1000; // any height will do + dummyTransactions[0].vout.resize(2); + dummyTransactions[0].vout[0].nValue = 11 * CENT; + dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; + dummyTransactions[0].vout[1].nValue = 50 * CENT; + dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; + AddCoins(coinsRet, dummyTransactions[0], nHeight); + + dummyTransactions[1].vout.resize(2); + dummyTransactions[1].vout[0].nValue = 21 * CENT; + dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID()); + dummyTransactions[1].vout[1].nValue = 22 * CENT; + dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID()); + AddCoins(coinsRet, dummyTransactions[1], nHeight); + + return dummyTransactions; +} + +BOOST_AUTO_TEST_CASE(buip055_op_return) +{ + // Check that a transaction with the invalid OP_RETURN is seen as invalid + CMutableTransaction tx; + tx.vout.resize(1); + tx.vout[0].nValue = 0; + tx.vout[0].scriptPubKey = CScript() << OP_RETURN << invalidOpReturn; + BOOST_CHECK(IsTxOpReturnInvalid(tx) == true); + + CKey key; + key.MakeNewKey(true); + + // Check that an arbitrary OP_RETURN is not invalid + tx.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("010203040506070809"); + BOOST_CHECK(IsTxOpReturnInvalid(tx) == false); + + // Check that a normal tx (without OP_RETURN) is not invalid + tx.vout[0].nValue = 50000; + tx.vout[0].scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(key.GetPubKey().GetID()) + << OP_EQUALVERIFY << OP_CHECKSIG; + BOOST_CHECK(IsTxOpReturnInvalid(tx) == false); + + // Check that a normal tx with the invalid OP_RETURN is invalid + tx.vout.resize(2); + tx.vout[1].scriptPubKey = CScript() << OP_RETURN << invalidOpReturn; + tx.vout[1].nValue = 0; + BOOST_CHECK(IsTxOpReturnInvalid(tx) == true); + + // OP_RETURN must be the first instruction for it to could as an invalid tx on the new fork + tx.vout[1].scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(key.GetPubKey().GetID()) + << OP_EQUALVERIFY << OP_RETURN << invalidOpReturn; + tx.vout[1].nValue = 0; + BOOST_CHECK(IsTxOpReturnInvalid(tx) == false); + + tx.vout[1].scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(key.GetPubKey().GetID()) + << OP_EQUALVERIFY << invalidOpReturn; + tx.vout[1].nValue = 0; + BOOST_CHECK(IsTxOpReturnInvalid(tx) == false); + + tx.vout[1].scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(key.GetPubKey().GetID()) + << OP_EQUALVERIFY << OP_RETURN << ParseHex("0") << invalidOpReturn; + BOOST_CHECK(IsTxOpReturnInvalid(tx) == false); +} + +BOOST_AUTO_TEST_CASE(buip055_sighash) +{ + LOCK(cs_main); + CBasicKeyStore keystore; + CCoinsView coinsDummy; + CCoinsViewCache coins(&coinsDummy); + std::vector dummyTransactions = SetupDummyInputs(keystore, coins); + + CMutableTransaction t; + t.vin.resize(1); + t.vin[0].prevout.hash = dummyTransactions[0].GetHash(); + t.vin[0].prevout.n = 1; + t.vout.resize(1); + t.vout[0].nValue = 90 * CENT; + CKey key; + key.MakeNewKey(true); + t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + + CTransaction tx(t); + + { + TransactionSignatureCreator tsc(&keystore, &tx, 0, 90 * CENT, SIGHASH_ALL); + const CScript &scriptPubKey = dummyTransactions[0].vout[0].scriptPubKey; + CScript &scriptSigRes = t.vin[0].scriptSig; + bool worked = ProduceSignature(tsc, scriptPubKey, scriptSigRes); + BOOST_CHECK(worked); + BOOST_CHECK(IsTxProbablyNewSigHash(t) == false); + } + + { + TransactionSignatureCreator tsc(&keystore, &tx, 0, 90 * CENT, SIGHASH_ALL | SIGHASH_FORKID); + const CScript &scriptPubKey = dummyTransactions[0].vout[0].scriptPubKey; + CScript &scriptSigRes = t.vin[0].scriptSig; + bool worked = ProduceSignature(tsc, scriptPubKey, scriptSigRes); + BOOST_CHECK(worked); + BOOST_CHECK(IsTxProbablyNewSigHash(t) == true); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp new file mode 100644 index 00000000..01a9bd7c --- /dev/null +++ b/src/test/checkblock_tests.cpp @@ -0,0 +1,68 @@ +// Copyright (c) 2013-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "clientversion.h" +#include "consensus/validation.h" +#include "main.h" // For CheckBlock +#include "primitives/block.h" +#include "test/test_bitcoin.h" +#include "utiltime.h" + +#include + +#include +#include +#include + +bool read_block(const std::string &filename, CBlock &block) +{ + namespace fs = boost::filesystem; + fs::path testFile = fs::current_path() / "data" / filename; +#ifdef TEST_DATA_DIR + if (!fs::exists(testFile)) + { + testFile = fs::path(BOOST_PP_STRINGIZE(TEST_DATA_DIR)) / filename; + } +#endif + FILE *fp = fopen(testFile.string().c_str(), "rb"); + if (!fp) + return false; + + fseek(fp, 8, SEEK_SET); // skip msgheader/size + + CAutoFile filein(fp, SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) + return false; + + filein >> block; + return true; +} + +BOOST_FIXTURE_TEST_SUITE(checkblock_tests, BasicTestingSetup) // BU harmonize suite name with filename + + +BOOST_AUTO_TEST_CASE(TestBlock) +{ + CBlock testblock; + if (read_block("testblock.dat", testblock)) + { + CValidationState state; + + uint64_t blockSize = ::GetSerializeSize(testblock, SER_NETWORK, PROTOCOL_VERSION); // 53298 B for test.dat + + BOOST_CHECK_MESSAGE(CheckBlock(testblock, state, false, false), "Basic CheckBlock failed"); + BOOST_CHECK_MESSAGE(!testblock.fExcessive, + "Block with size " << blockSize << " ought not to have been excessive when excessiveBlockSize is " + << excessiveBlockSize); + excessiveBlockSize = blockSize - 1; + BOOST_CHECK_MESSAGE(CheckBlock(testblock, state, false, false), "Basic CheckBlock failed"); + BOOST_CHECK_MESSAGE(testblock.fExcessive, + "Block with size " << blockSize << " ought to have been excessive when excessiveBlockSize is " + << excessiveBlockSize); + excessiveBlockSize = DEFAULT_EXCESSIVE_BLOCK_SIZE; // set it back to the default that other tests expect + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp new file mode 100644 index 00000000..1f6b5974 --- /dev/null +++ b/src/test/coins_tests.cpp @@ -0,0 +1,760 @@ +// Copyright (c) 2014-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "coins.h" +#include "consensus/validation.h" +#include "main.h" +#include "random.h" +#include "test/test_bitcoin.h" +#include "uint256.h" +#include "undo.h" + +#include +#include + +#include + +int ApplyTxInUndo(Coin &&undo, CCoinsViewCache &view, const COutPoint &out); +void UpdateCoins(const CTransaction &tx, + CValidationState &state, + CCoinsViewCache &inputs, + CTxUndo &txundo, + int nHeight); + +namespace +{ +//! equality test +bool operator==(const Coin &a, const Coin &b) +{ + // Empty Coin objects are always equal. + if (a.IsSpent() && b.IsSpent()) + return true; + return a.fCoinBase == b.fCoinBase && a.nHeight == b.nHeight && a.out == b.out; +} + +class CCoinsViewTest : public CCoinsView +{ + uint256 hashBestBlock_; + std::map map_; + +public: + bool GetCoin(const COutPoint &outpoint, Coin &coin) const + { + std::map::const_iterator it = map_.find(outpoint); + if (it == map_.end()) + { + return false; + } + coin = it->second; + if (coin.IsSpent() && insecure_rand() % 2 == 0) + { + // Randomly return false in case of an empty entry. + return false; + } + return true; + } + + bool HaveCoin(const COutPoint &outpoint) const + { + Coin coin; + return GetCoin(outpoint, coin); + } + + uint256 GetBestBlock() const { return hashBestBlock_; } + bool BatchWrite(CCoinsMap &mapCoins, + const uint256 &hashBlock, + const uint64_t nBestCoinHeight, + size_t &nChildCachedCoinsUsage) + { + for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) + { + if (it->second.flags & CCoinsCacheEntry::DIRTY) + { + // Same optimization used in CCoinsViewDB is to only write dirty entries. + map_[it->first] = it->second.coin; + if (it->second.coin.IsSpent() && insecure_rand() % 3 == 0) + { + // Randomly delete empty entries on write. + map_.erase(it->first); + } + nChildCachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); + mapCoins.erase(it++); + } + else + it++; + } + if (!hashBlock.IsNull()) + hashBestBlock_ = hashBlock; + return true; + } + + bool GetStats(CCoinsStats &stats) const { return false; } +}; + +class CCoinsViewCacheTest : public CCoinsViewCache +{ +public: + explicit CCoinsViewCacheTest(CCoinsView *base) : CCoinsViewCache(base) {} + void SelfTest() const + { + // Manually recompute the dynamic usage of the whole data, and compare it. + size_t ret = memusage::DynamicUsage(cacheCoins); + size_t count = 0; + for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) + { + ret += it->second.coin.DynamicMemoryUsage(); + ++count; + } + BOOST_CHECK_EQUAL(GetCacheSize(), count); + BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret); + } + + CCoinsMap &map() const { return cacheCoins; } + size_t &usage() const { return cachedCoinsUsage; } +}; +} + +BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup) + +static const unsigned int NUM_SIMULATION_ITERATIONS = 10000; + +// This is a large randomized insert/remove simulation test on a variable-size +// stack of caches on top of CCoinsViewTest. +// +// It will randomly create/update/delete Coin entries to a tip of caches, with +// txids picked from a limited list of random 256-bit hashes. Occasionally, a +// new tip is added to the stack of caches, or the tip is flushed and removed. +// +// During the process, booleans are kept to make sure that the randomized +// operation hits all branches. +BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) +{ + // Various coverage trackers. + bool removed_all_caches = false; + bool reached_4_caches = false; + bool added_an_entry = false; + bool added_an_unspendable_entry = false; + bool removed_an_entry = false; + bool updated_an_entry = false; + bool found_an_entry = false; + bool missed_an_entry = false; + bool uncached_an_entry = false; + + // A simple map to track what we expect the cache stack to represent. + std::map result; + + // The cache stack. + CCoinsViewTest base; // A CCoinsViewTest at the bottom. + std::vector stack; // A stack of CCoinsViewCaches on top. + stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache. + + // Use a limited set of random transaction ids, so we do test overwriting entries. + std::vector txids; + txids.resize(NUM_SIMULATION_ITERATIONS / 8); + for (unsigned int i = 0; i < txids.size(); i++) + { + txids[i] = GetRandHash(); + } + + for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) + { + // Do a random modification. + { + uint256 txid = txids[insecure_rand() % txids.size()]; // txid we're going to modify in this iteration. + Coin &coin = result[COutPoint(txid, 0)]; + const Coin &entry = (insecure_rand() % 500 == 0) ? AccessByTxid(*stack.back(), txid) : + stack.back()->AccessCoin(COutPoint(txid, 0)); + BOOST_CHECK(coin == entry); + + if (insecure_rand() % 5 == 0 || coin.IsSpent()) + { + Coin newcoin; + newcoin.out.nValue = insecure_rand(); + newcoin.nHeight = 1; + if (insecure_rand() % 16 == 0 && coin.IsSpent()) + { + newcoin.out.scriptPubKey.assign(1 + (insecure_rand() & 0x3F), OP_RETURN); + BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable()); + added_an_unspendable_entry = true; + } + else + { + // Random sizes so we can test memory usage accounting + newcoin.out.scriptPubKey.assign(insecure_rand() & 0x3F, 0); + (coin.IsSpent() ? added_an_entry : updated_an_entry) = true; + coin = newcoin; + } + stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), !coin.IsSpent() || insecure_rand() & 1); + } + else + { + removed_an_entry = true; + coin.Clear(); + stack.back()->SpendCoin(COutPoint(txid, 0)); + } + } + + // One every 10 iterations, remove a random entry from the cache + if (insecure_rand() % 10) + { + COutPoint out(txids[insecure_rand() % txids.size()], 0); + int cacheid = insecure_rand() % stack.size(); + stack[cacheid]->Uncache(out); + uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out); + } + + // One every 500 iterations, trim a random cache to zero + if (insecure_rand() % 500) + { + int cacheid = insecure_rand() % stack.size(); + stack[cacheid]->Trim(0); + } + + // Once every 1000 iterations and at the end, verify the full cache. + if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) + { + for (auto it = result.begin(); it != result.end(); it++) + { + bool have = stack.back()->HaveCoin(it->first); + const Coin &coin = stack.back()->AccessCoin(it->first); + BOOST_CHECK(have == !coin.IsSpent()); + BOOST_CHECK(coin == it->second); + if (coin.IsSpent()) + { + missed_an_entry = true; + } + else + { + BOOST_CHECK(stack.back()->HaveCoinInCache(it->first)); + found_an_entry = true; + } + } + BOOST_FOREACH (const CCoinsViewCacheTest *test, stack) + { + test->SelfTest(); + } + } + + // Every 100 iterations, flush an intermediate cache + if (insecure_rand() % 100 == 0) + { + if (stack.size() > 1 && insecure_rand() % 2 == 0) + { + unsigned int flushIndex = insecure_rand() % (stack.size() - 1); + stack[flushIndex]->Flush(); + } + } + + // Every 50 iterations, change the cache stack. + if (insecure_rand() % 50 == 0) + { + if (stack.size() > 0 && insecure_rand() % 2 == 0) + { + // Remove the top cache + stack.back()->Flush(); + delete stack.back(); + stack.pop_back(); + } + if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) + { + // Add a new cache + CCoinsView *tip = &base; + if (stack.size() > 0) + { + tip = stack.back(); + } + else + { + removed_all_caches = true; + } + + stack.push_back(new CCoinsViewCacheTest(tip)); + if (stack.size() == 4) + reached_4_caches = true; + } + } + } + + // Clean up the stack. + while (stack.size() > 0) + { + delete stack.back(); + stack.pop_back(); + } + + // Verify coverage. + BOOST_CHECK(removed_all_caches); + BOOST_CHECK(reached_4_caches); + BOOST_CHECK(added_an_entry); + BOOST_CHECK(added_an_unspendable_entry); + BOOST_CHECK(removed_an_entry); + BOOST_CHECK(updated_an_entry); + BOOST_CHECK(found_an_entry); + BOOST_CHECK(missed_an_entry); + BOOST_CHECK(uncached_an_entry); +} + +// Store of all necessary tx and undo data for next test +typedef std::map > UtxoData; +UtxoData utxoData; + +UtxoData::iterator FindRandomFrom(const std::set &utxoSet) +{ + assert(utxoSet.size()); + auto utxoSetIt = utxoSet.lower_bound(COutPoint(GetRandHash(), 0)); + if (utxoSetIt == utxoSet.end()) + { + utxoSetIt = utxoSet.begin(); + } + auto utxoDataIt = utxoData.find(*utxoSetIt); + assert(utxoDataIt != utxoData.end()); + return utxoDataIt; +} + +// This test is similar to the previous test +// except the emphasis is on testing the functionality of UpdateCoins +// random txs are created and UpdateCoins is used to update the cache stack +// In particular it is tested that spending a duplicate coinbase tx +// has the expected effect (the other duplicate is overwitten at all cache levels) + + +BOOST_AUTO_TEST_CASE(ccoins_serialization) +{ + // Good example + CDataStream ss1(ParseHex("97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35"), SER_DISK, CLIENT_VERSION); + Coin cc1; + ss1 >> cc1; + + CKeyID keyid1 = CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35"))); + CScript script1; + script1 << OP_DUP << OP_HASH160 << ToByteVector(keyid1) << OP_EQUALVERIFY << OP_CHECKSIG; + + BOOST_CHECK_EQUAL(cc1.fCoinBase, false); + BOOST_CHECK_EQUAL(cc1.nHeight, 203998); + BOOST_CHECK_EQUAL(cc1.out.nValue, 60000000000ULL); + BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(script1)); + + // Good example + CDataStream ss2(ParseHex("8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"), SER_DISK, CLIENT_VERSION); + Coin cc2; + ss2 >> cc2; + + CKeyID keyid2 = CKeyID(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"))); + CScript script2; + script2 << OP_DUP << OP_HASH160 << ToByteVector(keyid2) << OP_EQUALVERIFY << OP_CHECKSIG; + + BOOST_CHECK_EQUAL(cc2.fCoinBase, true); + BOOST_CHECK_EQUAL(cc2.nHeight, 120891); + BOOST_CHECK_EQUAL(cc2.out.nValue, 110397); + BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(script2)); + + // Smallest possible example + CDataStream ss3(ParseHex("000006"), SER_DISK, CLIENT_VERSION); + Coin cc3; + ss3 >> cc3; + BOOST_CHECK_EQUAL(cc3.fCoinBase, false); + BOOST_CHECK_EQUAL(cc3.nHeight, 0); + BOOST_CHECK_EQUAL(cc3.out.nValue, 0); + BOOST_CHECK_EQUAL(cc3.out.scriptPubKey.size(), 0); + + // scriptPubKey that ends beyond the end of the stream + CDataStream ss4(ParseHex("000007"), SER_DISK, CLIENT_VERSION); + try + { + Coin cc4; + ss4 >> cc4; + BOOST_CHECK_MESSAGE(false, "We should have thrown"); + } + catch (const std::ios_base::failure &e) + { + } + + // Very large scriptPubKey (3*10^9 bytes) past the end of the stream + CDataStream tmp(SER_DISK, CLIENT_VERSION); + uint64_t x = 3000000000ULL; + tmp << VARINT(x); + BOOST_CHECK_EQUAL(HexStr(tmp.begin(), tmp.end()), "8a95c0bb00"); + + CDataStream ss5(ParseHex("0008a95c0bb00"), SER_DISK, CLIENT_VERSION); + try + { + Coin cc5; + ss5 >> cc5; + BOOST_CHECK_MESSAGE(false, "We should have thrown"); + } + catch (const std::ios_base::failure &e) + { + } +} + +const static COutPoint OUTPOINT; +const static CAmount PRUNED = -1; +const static CAmount ABSENT = -2; +const static CAmount FAIL = -3; +const static CAmount VALUE1 = 100; +const static CAmount VALUE2 = 200; +const static CAmount VALUE3 = 300; +const static char DIRTY = CCoinsCacheEntry::DIRTY; +const static char FRESH = CCoinsCacheEntry::FRESH; +const static char NO_ENTRY = -1; + +const static auto FLAGS = {char(0), FRESH, DIRTY, char(DIRTY | FRESH)}; +const static auto CLEAN_FLAGS = {char(0), FRESH}; +const static auto ABSENT_FLAGS = {NO_ENTRY}; + +void SetCoinsValue(CAmount value, Coin &coin) +{ + assert(value != ABSENT); + coin.Clear(); + assert(coin.IsSpent()); + if (value != PRUNED) + { + coin.out.nValue = value; + coin.nHeight = 1; + assert(!coin.IsSpent()); + } +} + +size_t InsertCoinsMapEntry(CCoinsMap &map, CAmount value, char flags) +{ + if (value == ABSENT) + { + assert(flags == NO_ENTRY); + return 0; + } + assert(flags != NO_ENTRY); + CCoinsCacheEntry entry; + entry.flags = flags; + SetCoinsValue(value, entry.coin); + auto inserted = map.emplace(OUTPOINT, std::move(entry)); + assert(inserted.second); + return inserted.first->second.coin.DynamicMemoryUsage(); +} + +void GetCoinsMapEntry(const CCoinsMap &map, CAmount &value, char &flags) +{ + auto it = map.find(OUTPOINT); + if (it == map.end()) + { + value = ABSENT; + flags = NO_ENTRY; + } + else + { + if (it->second.coin.IsSpent()) + { + value = PRUNED; + } + else + { + value = it->second.coin.out.nValue; + } + flags = it->second.flags; + assert(flags != NO_ENTRY); + } +} + +void WriteCoinsViewEntry(CCoinsView &view, CAmount value, char flags) +{ + CCoinsMap map; + InsertCoinsMapEntry(map, value, flags); + uint256 hash; + hash.SetNull(); + size_t cacheusage = 0; + uint64_t bestCoinHeight = 0; + view.BatchWrite(map, hash, bestCoinHeight, cacheusage); +} + +class SingleEntryCacheTest +{ +public: + SingleEntryCacheTest(CAmount base_value, CAmount cache_value, char cache_flags) + { + WriteCoinsViewEntry(base, base_value, base_value == ABSENT ? NO_ENTRY : DIRTY); + cache.usage() += InsertCoinsMapEntry(cache.map(), cache_value, cache_flags); + } + + CCoinsView root; + CCoinsViewCacheTest base{&root}; + CCoinsViewCacheTest cache{&base}; +}; + +void CheckAccessCoin(CAmount base_value, + CAmount cache_value, + CAmount expected_value, + char cache_flags, + char expected_flags) +{ + SingleEntryCacheTest test(base_value, cache_value, cache_flags); + test.cache.AccessCoin(OUTPOINT); + test.cache.SelfTest(); + + CAmount result_value; + char result_flags; + GetCoinsMapEntry(test.cache.map(), result_value, result_flags); + BOOST_CHECK_EQUAL(result_value, expected_value); + BOOST_CHECK_EQUAL(result_flags, expected_flags); +} + +BOOST_AUTO_TEST_CASE(ccoins_access) +{ + /* Check AccessCoin behavior, requesting a coin from a cache view layered on + * top of a base view, and checking the resulting entry in the cache after + * the access. + * + * Base Cache Result Cache Result + * Value Value Value Flags Flags + */ + CheckAccessCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY); + CheckAccessCoin(ABSENT, PRUNED, PRUNED, 0, 0); + CheckAccessCoin(ABSENT, PRUNED, PRUNED, FRESH, FRESH); + CheckAccessCoin(ABSENT, PRUNED, PRUNED, DIRTY, DIRTY); + CheckAccessCoin(ABSENT, PRUNED, PRUNED, DIRTY | FRESH, DIRTY | FRESH); + CheckAccessCoin(ABSENT, VALUE2, VALUE2, 0, 0); + CheckAccessCoin(ABSENT, VALUE2, VALUE2, FRESH, FRESH); + CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY, DIRTY); + CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH); + CheckAccessCoin(PRUNED, ABSENT, PRUNED, NO_ENTRY, FRESH); + CheckAccessCoin(PRUNED, PRUNED, PRUNED, 0, 0); + CheckAccessCoin(PRUNED, PRUNED, PRUNED, FRESH, FRESH); + CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY); + CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY | FRESH, DIRTY | FRESH); + CheckAccessCoin(PRUNED, VALUE2, VALUE2, 0, 0); + CheckAccessCoin(PRUNED, VALUE2, VALUE2, FRESH, FRESH); + CheckAccessCoin(PRUNED, VALUE2, VALUE2, DIRTY, DIRTY); + CheckAccessCoin(PRUNED, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH); + CheckAccessCoin(VALUE1, ABSENT, VALUE1, NO_ENTRY, 0); + CheckAccessCoin(VALUE1, PRUNED, PRUNED, 0, 0); + CheckAccessCoin(VALUE1, PRUNED, PRUNED, FRESH, FRESH); + CheckAccessCoin(VALUE1, PRUNED, PRUNED, DIRTY, DIRTY); + CheckAccessCoin(VALUE1, PRUNED, PRUNED, DIRTY | FRESH, DIRTY | FRESH); + CheckAccessCoin(VALUE1, VALUE2, VALUE2, 0, 0); + CheckAccessCoin(VALUE1, VALUE2, VALUE2, FRESH, FRESH); + CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY, DIRTY); + CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH); +} + +void CheckSpendCoins(CAmount base_value, + CAmount cache_value, + CAmount expected_value, + char cache_flags, + char expected_flags) +{ + SingleEntryCacheTest test(base_value, cache_value, cache_flags); + test.cache.SpendCoin(OUTPOINT); + test.cache.SelfTest(); + + CAmount result_value; + char result_flags; + GetCoinsMapEntry(test.cache.map(), result_value, result_flags); + BOOST_CHECK_EQUAL(result_value, expected_value); + BOOST_CHECK_EQUAL(result_flags, expected_flags); +}; + +BOOST_AUTO_TEST_CASE(ccoins_spend) +{ + /* Check SpendCoin behavior, requesting a coin from a cache view layered on + * top of a base view, spending, and then checking + * the resulting entry in the cache after the modification. + * + * Base Cache Result Cache Result + * Value Value Value Flags Flags + */ + CheckSpendCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY); + CheckSpendCoins(ABSENT, PRUNED, PRUNED, 0, DIRTY); + CheckSpendCoins(ABSENT, PRUNED, ABSENT, FRESH, NO_ENTRY); + CheckSpendCoins(ABSENT, PRUNED, PRUNED, DIRTY, DIRTY); + CheckSpendCoins(ABSENT, PRUNED, ABSENT, DIRTY | FRESH, NO_ENTRY); + CheckSpendCoins(ABSENT, VALUE2, PRUNED, 0, DIRTY); + CheckSpendCoins(ABSENT, VALUE2, ABSENT, FRESH, NO_ENTRY); + CheckSpendCoins(ABSENT, VALUE2, PRUNED, DIRTY, DIRTY); + CheckSpendCoins(ABSENT, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY); + CheckSpendCoins(PRUNED, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY); + CheckSpendCoins(PRUNED, PRUNED, PRUNED, 0, DIRTY); + CheckSpendCoins(PRUNED, PRUNED, ABSENT, FRESH, NO_ENTRY); + CheckSpendCoins(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY); + CheckSpendCoins(PRUNED, PRUNED, ABSENT, DIRTY | FRESH, NO_ENTRY); + CheckSpendCoins(PRUNED, VALUE2, PRUNED, 0, DIRTY); + CheckSpendCoins(PRUNED, VALUE2, ABSENT, FRESH, NO_ENTRY); + CheckSpendCoins(PRUNED, VALUE2, PRUNED, DIRTY, DIRTY); + CheckSpendCoins(PRUNED, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY); + CheckSpendCoins(VALUE1, ABSENT, PRUNED, NO_ENTRY, DIRTY); + CheckSpendCoins(VALUE1, PRUNED, PRUNED, 0, DIRTY); + CheckSpendCoins(VALUE1, PRUNED, ABSENT, FRESH, NO_ENTRY); + CheckSpendCoins(VALUE1, PRUNED, PRUNED, DIRTY, DIRTY); + CheckSpendCoins(VALUE1, PRUNED, ABSENT, DIRTY | FRESH, NO_ENTRY); + CheckSpendCoins(VALUE1, VALUE2, PRUNED, 0, DIRTY); + CheckSpendCoins(VALUE1, VALUE2, ABSENT, FRESH, NO_ENTRY); + CheckSpendCoins(VALUE1, VALUE2, PRUNED, DIRTY, DIRTY); + CheckSpendCoins(VALUE1, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY); +} + +void CheckAddCoinBase(CAmount base_value, + CAmount cache_value, + CAmount modify_value, + CAmount expected_value, + char cache_flags, + char expected_flags, + bool coinbase) +{ + SingleEntryCacheTest test(base_value, cache_value, cache_flags); + + CAmount result_value; + char result_flags; + try + { + CTxOut output; + output.nValue = modify_value; + test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, coinbase), coinbase); + test.cache.SelfTest(); + GetCoinsMapEntry(test.cache.map(), result_value, result_flags); + } + catch (std::logic_error &e) + { + result_value = FAIL; + result_flags = NO_ENTRY; + } + + BOOST_CHECK_EQUAL(result_value, expected_value); + BOOST_CHECK_EQUAL(result_flags, expected_flags); +} + +// Simple wrapper for CheckAddCoinBase function above that loops through +// different possible base_values, making sure each one gives the same results. +// This wrapper lets the coins_add test below be shorter and less repetitive, +// while still verifying that the CoinsViewCache::AddCoin implementation +// ignores base values. +template +void CheckAddCoin(Args &&... args) +{ + for (CAmount base_value : {ABSENT, PRUNED, VALUE1}) + CheckAddCoinBase(base_value, std::forward(args)...); +} + +BOOST_AUTO_TEST_CASE(ccoins_add) +{ + /* Check AddCoin behavior, requesting a new coin from a cache view, + * writing a modification to the coin, and then checking the resulting + * entry in the cache after the modification. Verify behavior with the + * with the AddCoin potential_overwrite argument set to false, and to true. + * + * Cache Write Result Cache Result potential_overwrite + * Value Value Value Flags Flags + */ + CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY, DIRTY | FRESH, false); + CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY, DIRTY, true); + CheckAddCoin(PRUNED, VALUE3, VALUE3, 0, DIRTY | FRESH, false); + CheckAddCoin(PRUNED, VALUE3, VALUE3, 0, DIRTY, true); + CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH, DIRTY | FRESH, false); + CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH, DIRTY | FRESH, true); + CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY, DIRTY, false); + CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY, DIRTY, true); + CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY | FRESH, DIRTY | FRESH, false); + CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY | FRESH, DIRTY | FRESH, true); + CheckAddCoin(VALUE2, VALUE3, FAIL, 0, NO_ENTRY, false); + CheckAddCoin(VALUE2, VALUE3, VALUE3, 0, DIRTY, true); + CheckAddCoin(VALUE2, VALUE3, FAIL, FRESH, NO_ENTRY, false); + CheckAddCoin(VALUE2, VALUE3, VALUE3, FRESH, DIRTY | FRESH, true); + CheckAddCoin(VALUE2, VALUE3, FAIL, DIRTY, NO_ENTRY, false); + CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY, DIRTY, true); + CheckAddCoin(VALUE2, VALUE3, FAIL, DIRTY | FRESH, NO_ENTRY, false); + CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY | FRESH, DIRTY | FRESH, true); +} + +void CheckWriteCoins(CAmount parent_value, + CAmount child_value, + CAmount expected_value, + char parent_flags, + char child_flags, + char expected_flags) +{ + SingleEntryCacheTest test(ABSENT, parent_value, parent_flags); + + CAmount result_value; + char result_flags; + try + { + WriteCoinsViewEntry(test.cache, child_value, child_flags); + test.cache.SelfTest(); + GetCoinsMapEntry(test.cache.map(), result_value, result_flags); + } + catch (std::logic_error &e) + { + result_value = FAIL; + result_flags = NO_ENTRY; + } + + BOOST_CHECK_EQUAL(result_value, expected_value); + BOOST_CHECK_EQUAL(result_flags, expected_flags); +} + +BOOST_AUTO_TEST_CASE(ccoins_write) +{ + /* Check BatchWrite behavior, flushing one entry from a child cache to a + * parent cache, and checking the resulting entry in the parent cache + * after the write. + * + * Parent Child Result Parent Child Result + * Value Value Value Flags Flags Flags + */ + CheckWriteCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY, NO_ENTRY); + CheckWriteCoins(ABSENT, PRUNED, PRUNED, NO_ENTRY, DIRTY, DIRTY); + CheckWriteCoins(ABSENT, PRUNED, ABSENT, NO_ENTRY, DIRTY | FRESH, NO_ENTRY); + CheckWriteCoins(ABSENT, VALUE2, VALUE2, NO_ENTRY, DIRTY, DIRTY); + CheckWriteCoins(ABSENT, VALUE2, VALUE2, NO_ENTRY, DIRTY | FRESH, DIRTY | FRESH); + CheckWriteCoins(PRUNED, ABSENT, PRUNED, 0, NO_ENTRY, 0); + CheckWriteCoins(PRUNED, ABSENT, PRUNED, FRESH, NO_ENTRY, FRESH); + CheckWriteCoins(PRUNED, ABSENT, PRUNED, DIRTY, NO_ENTRY, DIRTY); + CheckWriteCoins(PRUNED, ABSENT, PRUNED, DIRTY | FRESH, NO_ENTRY, DIRTY | FRESH); + CheckWriteCoins(PRUNED, PRUNED, PRUNED, 0, DIRTY, DIRTY); + CheckWriteCoins(PRUNED, PRUNED, PRUNED, 0, DIRTY | FRESH, DIRTY); + CheckWriteCoins(PRUNED, PRUNED, ABSENT, FRESH, DIRTY, NO_ENTRY); + CheckWriteCoins(PRUNED, PRUNED, ABSENT, FRESH, DIRTY | FRESH, NO_ENTRY); + CheckWriteCoins(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY, DIRTY); + CheckWriteCoins(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY | FRESH, DIRTY); + CheckWriteCoins(PRUNED, PRUNED, ABSENT, DIRTY | FRESH, DIRTY, NO_ENTRY); + CheckWriteCoins(PRUNED, PRUNED, ABSENT, DIRTY | FRESH, DIRTY | FRESH, NO_ENTRY); + CheckWriteCoins(PRUNED, VALUE2, VALUE2, 0, DIRTY, DIRTY); + CheckWriteCoins(PRUNED, VALUE2, VALUE2, 0, DIRTY | FRESH, DIRTY); + CheckWriteCoins(PRUNED, VALUE2, VALUE2, FRESH, DIRTY, DIRTY | FRESH); + CheckWriteCoins(PRUNED, VALUE2, VALUE2, FRESH, DIRTY | FRESH, DIRTY | FRESH); + CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY, DIRTY, DIRTY); + CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY, DIRTY | FRESH, DIRTY); + CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY | FRESH, DIRTY, DIRTY | FRESH); + CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH, DIRTY | FRESH); + CheckWriteCoins(VALUE1, ABSENT, VALUE1, 0, NO_ENTRY, 0); + CheckWriteCoins(VALUE1, ABSENT, VALUE1, FRESH, NO_ENTRY, FRESH); + CheckWriteCoins(VALUE1, ABSENT, VALUE1, DIRTY, NO_ENTRY, DIRTY); + CheckWriteCoins(VALUE1, ABSENT, VALUE1, DIRTY | FRESH, NO_ENTRY, DIRTY | FRESH); + CheckWriteCoins(VALUE1, PRUNED, PRUNED, 0, DIRTY, DIRTY); + CheckWriteCoins(VALUE1, PRUNED, FAIL, 0, DIRTY | FRESH, NO_ENTRY); + CheckWriteCoins(VALUE1, PRUNED, ABSENT, FRESH, DIRTY, NO_ENTRY); + CheckWriteCoins(VALUE1, PRUNED, FAIL, FRESH, DIRTY | FRESH, NO_ENTRY); + CheckWriteCoins(VALUE1, PRUNED, PRUNED, DIRTY, DIRTY, DIRTY); + CheckWriteCoins(VALUE1, PRUNED, FAIL, DIRTY, DIRTY | FRESH, NO_ENTRY); + CheckWriteCoins(VALUE1, PRUNED, ABSENT, DIRTY | FRESH, DIRTY, NO_ENTRY); + CheckWriteCoins(VALUE1, PRUNED, FAIL, DIRTY | FRESH, DIRTY | FRESH, NO_ENTRY); + CheckWriteCoins(VALUE1, VALUE2, VALUE2, 0, DIRTY, DIRTY); + CheckWriteCoins(VALUE1, VALUE2, FAIL, 0, DIRTY | FRESH, NO_ENTRY); + CheckWriteCoins(VALUE1, VALUE2, VALUE2, FRESH, DIRTY, DIRTY | FRESH); + CheckWriteCoins(VALUE1, VALUE2, FAIL, FRESH, DIRTY | FRESH, NO_ENTRY); + CheckWriteCoins(VALUE1, VALUE2, VALUE2, DIRTY, DIRTY, DIRTY); + CheckWriteCoins(VALUE1, VALUE2, FAIL, DIRTY, DIRTY | FRESH, NO_ENTRY); + CheckWriteCoins(VALUE1, VALUE2, VALUE2, DIRTY | FRESH, DIRTY, DIRTY | FRESH); + CheckWriteCoins(VALUE1, VALUE2, FAIL, DIRTY | FRESH, DIRTY | FRESH, NO_ENTRY); + + // The checks above omit cases where the child flags are not DIRTY, since + // they would be too repetitive (the parent cache is never updated in these + // cases). The loop below covers these cases and makes sure the parent cache + // is always left unchanged. + for (CAmount parent_value : {ABSENT, PRUNED, VALUE1}) + for (CAmount child_value : {ABSENT, PRUNED, VALUE2}) + for (char parent_flags : parent_value == ABSENT ? ABSENT_FLAGS : FLAGS) + for (char child_flags : child_value == ABSENT ? ABSENT_FLAGS : CLEAN_FLAGS) + CheckWriteCoins(parent_value, child_value, parent_value, parent_flags, child_flags, parent_flags); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp new file mode 100644 index 00000000..bd6140a1 --- /dev/null +++ b/src/test/compress_tests.cpp @@ -0,0 +1,68 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "compressor.h" +#include "test/test_bitcoin.h" +#include "util.h" + +#include + +#include + +// amounts 0.00000001 .. 0.00100000 +#define NUM_MULTIPLES_UNIT 100000 + +// amounts 0.01 .. 100.00 +#define NUM_MULTIPLES_CENT 10000 + +// amounts 1 .. 10000 +#define NUM_MULTIPLES_1BTC 10000 + +// amounts 50 .. 21000000 +#define NUM_MULTIPLES_50BTC 420000 + +BOOST_FIXTURE_TEST_SUITE(compress_tests, BasicTestingSetup) + +bool static TestEncode(uint64_t in) +{ + return in == CTxOutCompressor::DecompressAmount(CTxOutCompressor::CompressAmount(in)); +} + +bool static TestDecode(uint64_t in) +{ + return in == CTxOutCompressor::CompressAmount(CTxOutCompressor::DecompressAmount(in)); +} + +bool static TestPair(uint64_t dec, uint64_t enc) +{ + return CTxOutCompressor::CompressAmount(dec) == enc && CTxOutCompressor::DecompressAmount(enc) == dec; +} + +BOOST_AUTO_TEST_CASE(compress_amounts) +{ + BOOST_CHECK(TestPair(0, 0x0)); + BOOST_CHECK(TestPair(1, 0x1)); + BOOST_CHECK(TestPair(CENT, 0x7)); + BOOST_CHECK(TestPair(COIN, 0x9)); + BOOST_CHECK(TestPair(50 * COIN, 0x32)); + BOOST_CHECK(TestPair(21000000 * COIN, 0x1406f40)); + + for (uint64_t i = 1; i <= NUM_MULTIPLES_UNIT; i++) + BOOST_CHECK(TestEncode(i)); + + for (uint64_t i = 1; i <= NUM_MULTIPLES_CENT; i++) + BOOST_CHECK(TestEncode(i * CENT)); + + for (uint64_t i = 1; i <= NUM_MULTIPLES_1BTC; i++) + BOOST_CHECK(TestEncode(i * COIN)); + + for (uint64_t i = 1; i <= NUM_MULTIPLES_50BTC; i++) + BOOST_CHECK(TestEncode(i * 50 * COIN)); + + for (uint64_t i = 0; i < 100000; i++) + BOOST_CHECK(TestDecode(i)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp new file mode 100644 index 00000000..c27c6ab4 --- /dev/null +++ b/src/test/crypto_tests.cpp @@ -0,0 +1,459 @@ +// Copyright (c) 2014-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "crypto/aes.h" +#include "crypto/hmac_sha256.h" +#include "crypto/hmac_sha512.h" +#include "crypto/ripemd160.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" +#include "crypto/sha512.h" +#include "random.h" +#include "test/test_bitcoin.h" +#include "utilstrencodings.h" + +#include + +#include +#include +#include +#include + +BOOST_FIXTURE_TEST_SUITE(crypto_tests, BasicTestingSetup) + +template +void TestVector(const Hasher &h, const In &in, const Out &out) +{ + Out hash; + BOOST_CHECK(out.size() == h.OUTPUT_SIZE); + hash.resize(out.size()); + { + // Test that writing the whole input string at once works. + Hasher(h).Write((unsigned char *)&in[0], in.size()).Finalize(&hash[0]); + BOOST_CHECK(hash == out); + } + for (int i = 0; i < 32; i++) + { + // Test that writing the string broken up in random pieces works. + Hasher hasher(h); + size_t pos = 0; + while (pos < in.size()) + { + size_t len = insecure_rand() % ((in.size() - pos + 1) / 2 + 1); + hasher.Write((unsigned char *)&in[pos], len); + pos += len; + if (pos > 0 && pos + 2 * out.size() > in.size() && pos < in.size()) + { + // Test that writing the rest at once to a copy of a hasher works. + Hasher(hasher).Write((unsigned char *)&in[pos], in.size() - pos).Finalize(&hash[0]); + BOOST_CHECK(hash == out); + } + } + hasher.Finalize(&hash[0]); + BOOST_CHECK(hash == out); + } +} + +void TestSHA1(const std::string &in, const std::string &hexout) { TestVector(CSHA1(), in, ParseHex(hexout)); } +void TestSHA256(const std::string &in, const std::string &hexout) { TestVector(CSHA256(), in, ParseHex(hexout)); } +void TestSHA512(const std::string &in, const std::string &hexout) { TestVector(CSHA512(), in, ParseHex(hexout)); } +void TestRIPEMD160(const std::string &in, const std::string &hexout) { TestVector(CRIPEMD160(), in, ParseHex(hexout)); } +void TestHMACSHA256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) +{ + std::vector key = ParseHex(hexkey); + TestVector(CHMAC_SHA256(&key[0], key.size()), ParseHex(hexin), ParseHex(hexout)); +} + +void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const std::string &hexout) +{ + std::vector key = ParseHex(hexkey); + TestVector(CHMAC_SHA512(&key[0], key.size()), ParseHex(hexin), ParseHex(hexout)); +} + +void TestAES128(const std::string &hexkey, const std::string &hexin, const std::string &hexout) +{ + std::vector key = ParseHex(hexkey); + std::vector in = ParseHex(hexin); + std::vector correctout = ParseHex(hexout); + std::vector buf, buf2; + + assert(key.size() == 16); + assert(in.size() == 16); + assert(correctout.size() == 16); + AES128Encrypt enc(&key[0]); + buf.resize(correctout.size()); + buf2.resize(correctout.size()); + enc.Encrypt(&buf[0], &in[0]); + BOOST_CHECK_EQUAL(HexStr(buf), HexStr(correctout)); + AES128Decrypt dec(&key[0]); + dec.Decrypt(&buf2[0], &buf[0]); + BOOST_CHECK_EQUAL(HexStr(buf2), HexStr(in)); +} + +void TestAES256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) +{ + std::vector key = ParseHex(hexkey); + std::vector in = ParseHex(hexin); + std::vector correctout = ParseHex(hexout); + std::vector buf; + + assert(key.size() == 32); + assert(in.size() == 16); + assert(correctout.size() == 16); + AES256Encrypt enc(&key[0]); + buf.resize(correctout.size()); + enc.Encrypt(&buf[0], &in[0]); + BOOST_CHECK(buf == correctout); + AES256Decrypt dec(&key[0]); + dec.Decrypt(&buf[0], &buf[0]); + BOOST_CHECK(buf == in); +} + +void TestAES128CBC(const std::string &hexkey, + const std::string &hexiv, + bool pad, + const std::string &hexin, + const std::string &hexout) +{ + std::vector key = ParseHex(hexkey); + std::vector iv = ParseHex(hexiv); + std::vector in = ParseHex(hexin); + std::vector correctout = ParseHex(hexout); + std::vector realout(in.size() + AES_BLOCKSIZE); + + // Encrypt the plaintext and verify that it equals the cipher + AES128CBCEncrypt enc(&key[0], &iv[0], pad); + int size = enc.Encrypt(&in[0], in.size(), &realout[0]); + realout.resize(size); + BOOST_CHECK(realout.size() == correctout.size()); + BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(" != ") + hexout); + + // Decrypt the cipher and verify that it equals the plaintext + std::vector decrypted(correctout.size()); + AES128CBCDecrypt dec(&key[0], &iv[0], pad); + size = dec.Decrypt(&correctout[0], correctout.size(), &decrypted[0]); + decrypted.resize(size); + BOOST_CHECK(decrypted.size() == in.size()); + BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(" != ") + hexin); + + // Encrypt and re-decrypt substrings of the plaintext and verify that they equal each-other + for (std::vector::iterator i(in.begin()); i != in.end(); ++i) + { + std::vector sub(i, in.end()); + std::vector subout(sub.size() + AES_BLOCKSIZE); + int size = enc.Encrypt(&sub[0], sub.size(), &subout[0]); + if (size != 0) + { + subout.resize(size); + std::vector subdecrypted(subout.size()); + size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]); + subdecrypted.resize(size); + BOOST_CHECK(decrypted.size() == in.size()); + BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub)); + } + } +} + +void TestAES256CBC(const std::string &hexkey, + const std::string &hexiv, + bool pad, + const std::string &hexin, + const std::string &hexout) +{ + std::vector key = ParseHex(hexkey); + std::vector iv = ParseHex(hexiv); + std::vector in = ParseHex(hexin); + std::vector correctout = ParseHex(hexout); + std::vector realout(in.size() + AES_BLOCKSIZE); + + // Encrypt the plaintext and verify that it equals the cipher + AES256CBCEncrypt enc(&key[0], &iv[0], pad); + int size = enc.Encrypt(&in[0], in.size(), &realout[0]); + realout.resize(size); + BOOST_CHECK(realout.size() == correctout.size()); + BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(" != ") + hexout); + + // Decrypt the cipher and verify that it equals the plaintext + std::vector decrypted(correctout.size()); + AES256CBCDecrypt dec(&key[0], &iv[0], pad); + size = dec.Decrypt(&correctout[0], correctout.size(), &decrypted[0]); + decrypted.resize(size); + BOOST_CHECK(decrypted.size() == in.size()); + BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(" != ") + hexin); + + // Encrypt and re-decrypt substrings of the plaintext and verify that they equal each-other + for (std::vector::iterator i(in.begin()); i != in.end(); ++i) + { + std::vector sub(i, in.end()); + std::vector subout(sub.size() + AES_BLOCKSIZE); + int size = enc.Encrypt(&sub[0], sub.size(), &subout[0]); + if (size != 0) + { + subout.resize(size); + std::vector subdecrypted(subout.size()); + size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]); + subdecrypted.resize(size); + BOOST_CHECK(decrypted.size() == in.size()); + BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub)); + } + } +} + +std::string LongTestString(void) +{ + std::string ret; + for (int i = 0; i < 200000; i++) + { + ret += (unsigned char)(i); + ret += (unsigned char)(i >> 4); + ret += (unsigned char)(i >> 8); + ret += (unsigned char)(i >> 12); + ret += (unsigned char)(i >> 16); + } + return ret; +} + +const std::string test1 = LongTestString(); + +BOOST_AUTO_TEST_CASE(ripemd160_testvectors) +{ + TestRIPEMD160("", "9c1185a5c5e9fc54612808977ee8f548b2258d31"); + TestRIPEMD160("abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); + TestRIPEMD160("message digest", "5d0689ef49d2fae572b881b123a85ffa21595f36"); + TestRIPEMD160("secure hash algorithm", "20397528223b6a5f4cbc2808aba0464e645544f9"); + TestRIPEMD160("RIPEMD160 is considered to be safe", "a7d78608c7af8a8e728778e81576870734122b66"); + TestRIPEMD160( + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "12a053384a9c0c88e405a06c27dcf49ada62eb2b"); + TestRIPEMD160( + "For this sample, this 63-byte string will be used as input data", "de90dbfee14b63fb5abf27c2ad4a82aaa5f27a11"); + TestRIPEMD160( + "This is exactly 64 bytes long, not counting the terminating byte", "eda31d51d3a623b81e19eb02e24ff65d27d67b37"); + TestRIPEMD160(std::string(1000000, 'a'), "52783243c1697bdbe16d37f97f68f08325dc1528"); + TestRIPEMD160(test1, "464243587bd146ea835cdf57bdae582f25ec45f1"); +} + +BOOST_AUTO_TEST_CASE(sha1_testvectors) +{ + TestSHA1("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"); + TestSHA1("abc", "a9993e364706816aba3e25717850c26c9cd0d89d"); + TestSHA1("message digest", "c12252ceda8be8994d5fa0290a47231c1d16aae3"); + TestSHA1("secure hash algorithm", "d4d6d2f0ebe317513bbd8d967d89bac5819c2f60"); + TestSHA1("SHA1 is considered to be safe", "f2b6650569ad3a8720348dd6ea6c497dee3a842a"); + TestSHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "84983e441c3bd26ebaae4aa1f95129e5e54670f1"); + TestSHA1( + "For this sample, this 63-byte string will be used as input data", "4f0ea5cd0585a23d028abdc1a6684e5a8094dc49"); + TestSHA1( + "This is exactly 64 bytes long, not counting the terminating byte", "fb679f23e7d1ce053313e66e127ab1b444397057"); + TestSHA1(std::string(1000000, 'a'), "34aa973cd4c4daa4f61eeb2bdbad27316534016f"); + TestSHA1(test1, "b7755760681cbfd971451668f32af5774f4656b5"); +} + +BOOST_AUTO_TEST_CASE(sha256_testvectors) +{ + TestSHA256("", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + TestSHA256("abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + TestSHA256("message digest", "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"); + TestSHA256("secure hash algorithm", "f30ceb2bb2829e79e4ca9753d35a8ecc00262d164cc077080295381cbd643f0d"); + TestSHA256("SHA256 is considered to be safe", "6819d915c73f4d1e77e4e1b52d1fa0f9cf9beaead3939f15874bd988e2a23630"); + TestSHA256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); + TestSHA256("For this sample, this 63-byte string will be used as input data", + "f08a78cbbaee082b052ae0708f32fa1e50c5c421aa772ba5dbb406a2ea6be342"); + TestSHA256("This is exactly 64 bytes long, not counting the terminating byte", + "ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8"); + TestSHA256("As Bitcoin relies on 80 byte header hashes, we want to have an example for that.", + "7406e8de7d6e4fffc573daef05aefb8806e7790f55eab5576f31349743cca743"); + TestSHA256(std::string(1000000, 'a'), "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); + TestSHA256(test1, "a316d55510b49662420f49d145d42fb83f31ef8dc016aa4e32df049991a91e26"); +} + +BOOST_AUTO_TEST_CASE(sha512_testvectors) +{ + TestSHA512("", "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce" + "47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"); + TestSHA512("abc", "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"); + TestSHA512("message digest", "107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f33" + "09e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c"); + TestSHA512("secure hash algorithm", "7746d91f3de30c68cec0dd693120a7e8b04d8073cb699bdce1a3f64127bca7a3" + "d5db502e814bb63c063a7a5043b2df87c61133395f4ad1edca7fcf4b30c3236e"); + TestSHA512("SHA512 is considered to be safe", "099e6468d889e1c79092a89ae925a9499b5408e01b66cb5b0a3bd0dfa51a9964" + "6b4a3901caab1318189f74cd8cf2e941829012f2449df52067d3dd5b978456c2"); + TestSHA512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c335" + "96fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445"); + TestSHA512("For this sample, this 63-byte string will be used as input data", + "b3de4afbc516d2478fe9b518d063bda6c8dd65fc38402dd81d1eb7364e72fb6e" + "6663cf6d2771c8f5a6da09601712fb3d2a36c6ffea3e28b0818b05b0a8660766"); + TestSHA512("This is exactly 64 bytes long, not counting the terminating byte", + "70aefeaa0e7ac4f8fe17532d7185a289bee3b428d950c14fa8b713ca09814a38" + "7d245870e007a80ad97c369d193e41701aa07f3221d15f0e65a1ff970cedf030"); + TestSHA512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno" + "ijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" + "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909"); + TestSHA512(std::string(1000000, 'a'), "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" + "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"); + TestSHA512(test1, "40cac46c147e6131c5193dd5f34e9d8bb4951395f27b08c558c65ff4ba2de594" + "37de8c3ef5459d76a52cedc02dc499a3c9ed9dedbfb3281afd9653b8a112fafc"); +} + +BOOST_AUTO_TEST_CASE(hmac_sha256_testvectors) +{ + // test cases 1, 2, 3, 4, 6 and 7 of RFC 4231 + TestHMACSHA256("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "4869205468657265", + "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"); + TestHMACSHA256("4a656665", "7768617420646f2079612077616e7420666f72206e6f7468696e673f", + "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"); + TestHMACSHA256("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" + "dddddddddddddddddddddddddddddddddddd", + "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe"); + TestHMACSHA256("0102030405060708090a0b0c0d0e0f10111213141516171819", + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"); + TestHMACSHA256("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaa", + "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a" + "65204b6579202d2048617368204b6579204669727374", + "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"); + TestHMACSHA256("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaa", + "5468697320697320612074657374207573696e672061206c6172676572207468" + "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" + "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" + "647320746f20626520686173686564206265666f7265206265696e6720757365" + "642062792074686520484d414320616c676f726974686d2e", + "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"); +} + +BOOST_AUTO_TEST_CASE(hmac_sha512_testvectors) +{ + // test cases 1, 2, 3, 4, 6 and 7 of RFC 4231 + TestHMACSHA512("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "4869205468657265", + "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cde" + "daa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"); + TestHMACSHA512("4a656665", "7768617420646f2079612077616e7420666f72206e6f7468696e673f", + "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554" + "9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737"); + TestHMACSHA512("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" + "dddddddddddddddddddddddddddddddddddd", + "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39" + "bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb"); + TestHMACSHA512("0102030405060708090a0b0c0d0e0f10111213141516171819", + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3db" + "a91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd"); + TestHMACSHA512("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaa", + "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a" + "65204b6579202d2048617368204b6579204669727374", + "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f352" + "6b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598"); + TestHMACSHA512("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaa", + "5468697320697320612074657374207573696e672061206c6172676572207468" + "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" + "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" + "647320746f20626520686173686564206265666f7265206265696e6720757365" + "642062792074686520484d414320616c676f726974686d2e", + "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944" + "b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58"); +} + +BOOST_AUTO_TEST_CASE(aes_testvectors) +{ + // AES test vectors from FIPS 197. + TestAES128( + "000102030405060708090a0b0c0d0e0f", "00112233445566778899aabbccddeeff", "69c4e0d86a7b0430d8cdb78070b4c55a"); + TestAES256("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "00112233445566778899aabbccddeeff", + "8ea2b7ca516745bfeafc49904b496089"); + + // AES-ECB test vectors from NIST sp800-38a. + TestAES128( + "2b7e151628aed2a6abf7158809cf4f3c", "6bc1bee22e409f96e93d7e117393172a", "3ad77bb40d7a3660a89ecaf32466ef97"); + TestAES128( + "2b7e151628aed2a6abf7158809cf4f3c", "ae2d8a571e03ac9c9eb76fac45af8e51", "f5d3d58503b9699de785895a96fdbaaf"); + TestAES128( + "2b7e151628aed2a6abf7158809cf4f3c", "30c81c46a35ce411e5fbc1191a0a52ef", "43b1cd7f598ece23881b00e3ed030688"); + TestAES128( + "2b7e151628aed2a6abf7158809cf4f3c", "f69f2445df4f9b17ad2b417be66c3710", "7b0c785e27e8ad3f8223207104725dd4"); + TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "6bc1bee22e409f96e93d7e117393172a", + "f3eed1bdb5d2a03c064b5a7e3db181f8"); + TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "ae2d8a571e03ac9c9eb76fac45af8e51", + "591ccb10d410ed26dc5ba74a31362870"); + TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "30c81c46a35ce411e5fbc1191a0a52ef", + "b6ed21b99ca6f4f9f153e7b1beafed1d"); + TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "f69f2445df4f9b17ad2b417be66c3710", + "23304b7a39f9f3ff067d8d8f9e24ecc7"); +} + +BOOST_AUTO_TEST_CASE(aes_cbc_testvectors) +{ + // NIST AES CBC 128-bit encryption test-vectors + TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "000102030405060708090A0B0C0D0E0F", false, + "6bc1bee22e409f96e93d7e117393172a", "7649abac8119b246cee98e9b12e9197d"); + TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "7649ABAC8119B246CEE98E9B12E9197D", false, + "ae2d8a571e03ac9c9eb76fac45af8e51", "5086cb9b507219ee95db113a917678b2"); + TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "5086cb9b507219ee95db113a917678b2", false, + "30c81c46a35ce411e5fbc1191a0a52ef", "73bed6b8e3c1743b7116e69e22229516"); + TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "73bed6b8e3c1743b7116e69e22229516", false, + "f69f2445df4f9b17ad2b417be66c3710", "3ff1caa1681fac09120eca307586e1a7"); + + // The same vectors with padding enabled + TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "000102030405060708090A0B0C0D0E0F", true, + "6bc1bee22e409f96e93d7e117393172a", "7649abac8119b246cee98e9b12e9197d8964e0b149c10b7b682e6e39aaeb731c"); + TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "7649ABAC8119B246CEE98E9B12E9197D", true, + "ae2d8a571e03ac9c9eb76fac45af8e51", "5086cb9b507219ee95db113a917678b255e21d7100b988ffec32feeafaf23538"); + TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "5086cb9b507219ee95db113a917678b2", true, + "30c81c46a35ce411e5fbc1191a0a52ef", "73bed6b8e3c1743b7116e69e22229516f6eccda327bf8e5ec43718b0039adceb"); + TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "73bed6b8e3c1743b7116e69e22229516", true, + "f69f2445df4f9b17ad2b417be66c3710", "3ff1caa1681fac09120eca307586e1a78cb82807230e1321d3fae00d18cc2012"); + + // NIST AES CBC 256-bit encryption test-vectors + TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "000102030405060708090A0B0C0D0E0F", false, "6bc1bee22e409f96e93d7e117393172a", + "f58c4c04d6e5f1ba779eabfb5f7bfbd6"); + TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "F58C4C04D6E5F1BA779EABFB5F7BFBD6", false, "ae2d8a571e03ac9c9eb76fac45af8e51", + "9cfc4e967edb808d679f777bc6702c7d"); + TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "9CFC4E967EDB808D679F777BC6702C7D", false, "30c81c46a35ce411e5fbc1191a0a52ef", + "39f23369a9d9bacfa530e26304231461"); + TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "39F23369A9D9BACFA530E26304231461", false, "f69f2445df4f9b17ad2b417be66c3710", + "b2eb05e2c39be9fcda6c19078c6a9d1b"); + + // The same vectors with padding enabled + TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "000102030405060708090A0B0C0D0E0F", true, "6bc1bee22e409f96e93d7e117393172a", + "f58c4c04d6e5f1ba779eabfb5f7bfbd6485a5c81519cf378fa36d42b8547edc0"); + TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "F58C4C04D6E5F1BA779EABFB5F7BFBD6", true, "ae2d8a571e03ac9c9eb76fac45af8e51", + "9cfc4e967edb808d679f777bc6702c7d3a3aa5e0213db1a9901f9036cf5102d2"); + TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "9CFC4E967EDB808D679F777BC6702C7D", true, "30c81c46a35ce411e5fbc1191a0a52ef", + "39f23369a9d9bacfa530e263042314612f8da707643c90a6f732b3de1d3f5cee"); + TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "39F23369A9D9BACFA530E26304231461", true, "f69f2445df4f9b17ad2b417be66c3710", + "b2eb05e2c39be9fcda6c19078c6a9d1b3f461796d6b0d6b2e0c2a72b4d80e644"); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/data/README.md b/src/test/data/README.md new file mode 100644 index 00000000..2463daa4 --- /dev/null +++ b/src/test/data/README.md @@ -0,0 +1,12 @@ +Description +------------ + +This directory contains data-driven tests for various aspects of Bitcoin. + +License +-------- + +The data files in this directory are distributed under the MIT software +license, see the accompanying file COPYING or +http://www.opensource.org/licenses/mit-license.php. + diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json new file mode 100644 index 00000000..3bf80ca4 --- /dev/null +++ b/src/test/data/bitcoin-util-test.json @@ -0,0 +1,90 @@ +[ + { "exec": "././bitcoin-tx", + "args": ["-create"], + "output_cmp": "blanktx.hex" + }, + { "exec": "./bitcoin-tx", + "args": ["-"], + "input": "blanktx.hex", + "output_cmp": "blanktx.hex" + }, + { "exec": "./bitcoin-tx", + "args": ["-", "delin=1"], + "input": "tx394b54bb.hex", + "output_cmp": "tt-delin1-out.hex" + }, + { "exec": "./bitcoin-tx", + "args": ["-", "delin=31"], + "input": "tx394b54bb.hex", + "return_code": 1 + }, + { "exec": "./bitcoin-tx", + "args": ["-", "delout=1"], + "input": "tx394b54bb.hex", + "output_cmp": "tt-delout1-out.hex" + }, + { "exec": "./bitcoin-tx", + "args": ["-", "delout=2"], + "input": "tx394b54bb.hex", + "return_code": 1 + }, + { "exec": "./bitcoin-tx", + "args": ["-", "locktime=317000"], + "input": "tx394b54bb.hex", + "output_cmp": "tt-locktime317000-out.hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18", + "in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1", + "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o", + "outaddr=4:1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46"], + "output_cmp": "txcreate1.hex" + }, + { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:"], + "output_cmp": "txcreate2.hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", + "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", + "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", + "sign=ALL", + "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"], + "output_cmp": "txcreatesign.hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "outdata=4:badhexdata"], + "return_code": 1 + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "outdata=badhexdata"], + "return_code": 1 + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o", + "outdata=4:54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"], + "output_cmp": "txcreatedata1.hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o", + "outdata=54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"], + "output_cmp": "txcreatedata2.hex" + } +] diff --git a/src/test/data/blanktx.hex b/src/test/data/blanktx.hex new file mode 100644 index 00000000..36b6f00f --- /dev/null +++ b/src/test/data/blanktx.hex @@ -0,0 +1 @@ +01000000000000000000 diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json new file mode 100644 index 00000000..d029886e --- /dev/null +++ b/src/test/data/script_tests.json @@ -0,0 +1,1900 @@ +[ +["Format is: [scriptSig, scriptPubKey, flags, expected_scripterror, ... comments]"], +["It is evaluated as if there was a crediting coinbase transaction with two 0"], +["pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey,"], +["followed by a spending transaction which spends this output as only input (and"], +["correct prevout hash), using the given scriptSig. All nLockTimes are 0, all"], +["nSequences are max."], + +["", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "Test the test: we should have an empty stack after scriptSig evaluation"], +[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "and multiple spaces should not change that."], +[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "OK", "Similarly whitespace around and between symbols"], +["1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "OK"], +[" 1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "OK"], +["1 2 ", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "OK"], +[" 1 2 ", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "OK"], + +["1", "", "P2SH,STRICTENC", "OK"], +["0x02 0x01 0x00", "", "P2SH,STRICTENC", "OK", "all bytes are significant, not only the last one"], +["0x09 0x00000000 0x00000000 0x10", "", "P2SH,STRICTENC", "OK", "equals zero when cast to Int64"], + +["0x01 0x0b", "11 EQUAL", "P2SH,STRICTENC", "OK", "push 1 byte"], +["0x02 0x417a", "'Az' EQUAL", "P2SH,STRICTENC", "OK"], +["0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a", + "'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL", "P2SH,STRICTENC", "OK", "push 75 bytes"], + +["0x4c 0x01 0x07","7 EQUAL", "P2SH,STRICTENC", "OK", "0x4c is OP_PUSHDATA1"], +["0x4d 0x0100 0x08","8 EQUAL", "P2SH,STRICTENC", "OK", "0x4d is OP_PUSHDATA2"], +["0x4e 0x01000000 0x09","9 EQUAL", "P2SH,STRICTENC", "OK", "0x4e is OP_PUSHDATA4"], + +["0x4c 0x00","0 EQUAL", "P2SH,STRICTENC", "OK"], +["0x4d 0x0000","0 EQUAL", "P2SH,STRICTENC", "OK"], +["0x4e 0x00000000","0 EQUAL", "P2SH,STRICTENC", "OK"], +["0x4f 1000 ADD","999 EQUAL", "P2SH,STRICTENC", "OK"], +["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "OK", "0x50 is reserved (ok if not executed)"], +["0x51", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "OK", "0x51 through 0x60 push 1 through 16 onto stack"], +["1","NOP", "P2SH,STRICTENC", "OK"], +["0", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "VER non-functional (ok if not executed)"], +["0", "IF RESERVED RESERVED1 RESERVED2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "RESERVED ok in un-executed IF"], + +["1", "DUP IF ENDIF", "P2SH,STRICTENC", "OK"], +["1", "IF 1 ENDIF", "P2SH,STRICTENC", "OK"], +["1", "DUP IF ELSE ENDIF", "P2SH,STRICTENC", "OK"], +["1", "IF 1 ELSE ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], + +["1 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], +["1 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], +["1 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], +["0 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], + +["1 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], +["1 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], +["1 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], +["0 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], + +["0", "IF 0 ELSE 1 ELSE 0 ENDIF", "P2SH,STRICTENC", "OK", "Multiple ELSE's are valid and executed inverts on each ELSE encountered"], +["1", "IF 1 ELSE 0 ELSE ENDIF", "P2SH,STRICTENC", "OK"], +["1", "IF ELSE 0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["1", "IF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL", "P2SH,STRICTENC", "OK"], +["'' 1", "IF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL", "P2SH,STRICTENC", "OK"], + +["1", "NOTIF 0 ELSE 1 ELSE 0 ENDIF", "P2SH,STRICTENC", "OK", "Multiple ELSE's are valid and execution inverts on each ELSE encountered"], +["0", "NOTIF 1 ELSE 0 ELSE ENDIF", "P2SH,STRICTENC", "OK"], +["0", "NOTIF ELSE 0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "NOTIF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL", "P2SH,STRICTENC", "OK"], +["'' 0", "NOTIF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL", "P2SH,STRICTENC", "OK"], + +["0", "IF 1 IF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 1 IF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL", "P2SH,STRICTENC", "OK", "Nested ELSE ELSE"], +["1", "NOTIF 0 NOTIF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 0 NOTIF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL", "P2SH,STRICTENC", "OK"], + +["0", "IF RETURN ENDIF 1", "P2SH,STRICTENC", "OK", "RETURN only works if executed"], + +["1 1", "VERIFY", "P2SH,STRICTENC", "OK"], +["1 0x05 0x01 0x00 0x00 0x00 0x00", "VERIFY", "P2SH,STRICTENC", "OK", "values >4 bytes can be cast to boolean"], +["1 0x01 0x80", "IF 0 ENDIF", "P2SH,STRICTENC", "OK", "negative 0 is false"], + +["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL", "P2SH,STRICTENC", "OK"], +["'gavin_was_here' TOALTSTACK 11 FROMALTSTACK", "'gavin_was_here' EQUALVERIFY 11 EQUAL", "P2SH,STRICTENC", "OK"], + +["0 IFDUP", "DEPTH 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC", "OK"], +["1 IFDUP", "DEPTH 2 EQUALVERIFY 1 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "OK"], +["0x05 0x0100000000 IFDUP", "DEPTH 2 EQUALVERIFY 0x05 0x0100000000 EQUAL", "P2SH,STRICTENC", "OK", "IFDUP dups non ints"], +["0 DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["0", "DUP 1 ADD 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC", "OK"], +["0 1", "NIP", "P2SH,STRICTENC", "OK"], +["1 0", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC", "OK"], +["22 21 20", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "ROT 22 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "ROT DROP 20 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "ROT DROP DROP 21 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "ROT ROT 21 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "ROT ROT ROT 20 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 24 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT DROP 25 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 2DROP 20 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 2DROP DROP 21 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 2DROP 2DROP 22 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 2DROP 2DROP DROP 23 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 2ROT 22 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 2ROT 2ROT 20 EQUAL", "P2SH,STRICTENC", "OK"], +["1 0", "SWAP 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC", "OK"], +["0 1", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC", "OK"], +["13 14", "2DUP ROT EQUALVERIFY EQUAL", "P2SH,STRICTENC", "OK"], +["-1 0 1 2", "3DUP DEPTH 7 EQUALVERIFY ADD ADD 3 EQUALVERIFY 2DROP 0 EQUALVERIFY", "P2SH,STRICTENC", "OK"], +["1 2 3 5", "2OVER ADD ADD 8 EQUALVERIFY ADD ADD 6 EQUAL", "P2SH,STRICTENC", "OK"], +["1 3 5 7", "2SWAP ADD 4 EQUALVERIFY ADD 12 EQUAL", "P2SH,STRICTENC", "OK"], +["0", "SIZE 0 EQUAL", "P2SH,STRICTENC", "OK"], +["1", "SIZE 1 EQUAL", "P2SH,STRICTENC", "OK"], +["127", "SIZE 1 EQUAL", "P2SH,STRICTENC", "OK"], +["128", "SIZE 2 EQUAL", "P2SH,STRICTENC", "OK"], +["32767", "SIZE 2 EQUAL", "P2SH,STRICTENC", "OK"], +["32768", "SIZE 3 EQUAL", "P2SH,STRICTENC", "OK"], +["8388607", "SIZE 3 EQUAL", "P2SH,STRICTENC", "OK"], +["8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC", "OK"], +["2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC", "OK"], +["2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], +["549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], +["549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC", "OK"], +["9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC", "OK"], +["-1", "SIZE 1 EQUAL", "P2SH,STRICTENC", "OK"], +["-127", "SIZE 1 EQUAL", "P2SH,STRICTENC", "OK"], +["-128", "SIZE 2 EQUAL", "P2SH,STRICTENC", "OK"], +["-32767", "SIZE 2 EQUAL", "P2SH,STRICTENC", "OK"], +["-32768", "SIZE 3 EQUAL", "P2SH,STRICTENC", "OK"], +["-8388607", "SIZE 3 EQUAL", "P2SH,STRICTENC", "OK"], +["-8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC", "OK"], +["-2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC", "OK"], +["-2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], +["-549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], +["-549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC", "OK"], +["-9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC", "OK"], +["'abcdefghijklmnopqrstuvwxyz'", "SIZE 26 EQUAL", "P2SH,STRICTENC", "OK"], + +["42", "SIZE 1 EQUALVERIFY 42 EQUAL", "P2SH,STRICTENC", "OK", "SIZE does not consume argument"], + +["2 -2 ADD", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["2147483647 -2147483647 ADD", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["-1 -1 ADD", "-2 EQUAL", "P2SH,STRICTENC", "OK"], + +["0 0","EQUAL", "P2SH,STRICTENC", "OK"], +["1 1 ADD", "2 EQUAL", "P2SH,STRICTENC", "OK"], +["1 1ADD", "2 EQUAL", "P2SH,STRICTENC", "OK"], +["111 1SUB", "110 EQUAL", "P2SH,STRICTENC", "OK"], +["111 1 ADD 12 SUB", "100 EQUAL", "P2SH,STRICTENC", "OK"], +["0 ABS", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["16 ABS", "16 EQUAL", "P2SH,STRICTENC", "OK"], +["-16 ABS", "-16 NEGATE EQUAL", "P2SH,STRICTENC", "OK"], +["0 NOT", "NOP", "P2SH,STRICTENC", "OK"], +["1 NOT", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["11 NOT", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["0 0NOTEQUAL", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["1 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC", "OK"], +["111 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC", "OK"], +["-111 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC", "OK"], +["1 1 BOOLAND", "NOP", "P2SH,STRICTENC", "OK"], +["1 0 BOOLAND", "NOT", "P2SH,STRICTENC", "OK"], +["0 1 BOOLAND", "NOT", "P2SH,STRICTENC", "OK"], +["0 0 BOOLAND", "NOT", "P2SH,STRICTENC", "OK"], +["16 17 BOOLAND", "NOP", "P2SH,STRICTENC", "OK"], +["1 1 BOOLOR", "NOP", "P2SH,STRICTENC", "OK"], +["1 0 BOOLOR", "NOP", "P2SH,STRICTENC", "OK"], +["0 1 BOOLOR", "NOP", "P2SH,STRICTENC", "OK"], +["0 0 BOOLOR", "NOT", "P2SH,STRICTENC", "OK"], +["16 17 BOOLOR", "NOP", "P2SH,STRICTENC", "OK"], +["11 10 1 ADD", "NUMEQUAL", "P2SH,STRICTENC", "OK"], +["11 10 1 ADD", "NUMEQUALVERIFY 1", "P2SH,STRICTENC", "OK"], +["11 10 1 ADD", "NUMNOTEQUAL NOT", "P2SH,STRICTENC", "OK"], +["111 10 1 ADD", "NUMNOTEQUAL", "P2SH,STRICTENC", "OK"], +["11 10", "LESSTHAN NOT", "P2SH,STRICTENC", "OK"], +["4 4", "LESSTHAN NOT", "P2SH,STRICTENC", "OK"], +["10 11", "LESSTHAN", "P2SH,STRICTENC", "OK"], +["-11 11", "LESSTHAN", "P2SH,STRICTENC", "OK"], +["-11 -10", "LESSTHAN", "P2SH,STRICTENC", "OK"], +["11 10", "GREATERTHAN", "P2SH,STRICTENC", "OK"], +["4 4", "GREATERTHAN NOT", "P2SH,STRICTENC", "OK"], +["10 11", "GREATERTHAN NOT", "P2SH,STRICTENC", "OK"], +["-11 11", "GREATERTHAN NOT", "P2SH,STRICTENC", "OK"], +["-11 -10", "GREATERTHAN NOT", "P2SH,STRICTENC", "OK"], +["11 10", "LESSTHANOREQUAL NOT", "P2SH,STRICTENC", "OK"], +["4 4", "LESSTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["10 11", "LESSTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["-11 11", "LESSTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["-11 -10", "LESSTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["11 10", "GREATERTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["4 4", "GREATERTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["10 11", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC", "OK"], +["-11 11", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC", "OK"], +["-11 -10", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC", "OK"], +["1 0 MIN", "0 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0 1 MIN", "0 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["-1 0 MIN", "-1 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0 -2147483647 MIN", "-2147483647 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["2147483647 0 MAX", "2147483647 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0 100 MAX", "100 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["-100 0 MAX", "0 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0 -2147483647 MAX", "0 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0 0 1", "WITHIN", "P2SH,STRICTENC", "OK"], +["1 0 1", "WITHIN NOT", "P2SH,STRICTENC", "OK"], +["0 -2147483647 2147483647", "WITHIN", "P2SH,STRICTENC", "OK"], +["-1 -100 100", "WITHIN", "P2SH,STRICTENC", "OK"], +["11 -100 100", "WITHIN", "P2SH,STRICTENC", "OK"], +["-2147483647 -100 100", "WITHIN NOT", "P2SH,STRICTENC", "OK"], +["2147483647 -100 100", "WITHIN NOT", "P2SH,STRICTENC", "OK"], + +["2147483647 2147483647 SUB", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["2147483647 DUP ADD", "4294967294 EQUAL", "P2SH,STRICTENC", "OK", ">32 bit EQUAL is valid"], +["2147483647 NEGATE DUP ADD", "-4294967294 EQUAL", "P2SH,STRICTENC", "OK"], + +["''", "RIPEMD160 0x14 0x9c1185a5c5e9fc54612808977ee8f548b2258d31 EQUAL", "P2SH,STRICTENC", "OK"], +["'a'", "RIPEMD160 0x14 0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe EQUAL", "P2SH,STRICTENC", "OK"], +["'abcdefghijklmnopqrstuvwxyz'", "RIPEMD160 0x14 0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc EQUAL", "P2SH,STRICTENC", "OK"], +["''", "SHA1 0x14 0xda39a3ee5e6b4b0d3255bfef95601890afd80709 EQUAL", "P2SH,STRICTENC", "OK"], +["'a'", "SHA1 0x14 0x86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 EQUAL", "P2SH,STRICTENC", "OK"], +["'abcdefghijklmnopqrstuvwxyz'", "SHA1 0x14 0x32d10c7b8cf96570ca04ce37f2a19d84240d3a89 EQUAL", "P2SH,STRICTENC", "OK"], +["''", "SHA256 0x20 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 EQUAL", "P2SH,STRICTENC", "OK"], +["'a'", "SHA256 0x20 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb EQUAL", "P2SH,STRICTENC", "OK"], +["'abcdefghijklmnopqrstuvwxyz'", "SHA256 0x20 0x71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 EQUAL", "P2SH,STRICTENC", "OK"], +["''", "DUP HASH160 SWAP SHA256 RIPEMD160 EQUAL", "P2SH,STRICTENC", "OK"], +["''", "DUP HASH256 SWAP SHA256 SHA256 EQUAL", "P2SH,STRICTENC", "OK"], +["''", "NOP HASH160 0x14 0xb472a266d0bd89c13706a4132ccfb16f7c3b9fcb EQUAL", "P2SH,STRICTENC", "OK"], +["'a'", "HASH160 NOP 0x14 0x994355199e516ff76c4fa4aab39337b9d84cf12b EQUAL", "P2SH,STRICTENC", "OK"], +["'abcdefghijklmnopqrstuvwxyz'", "HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL", "P2SH,STRICTENC", "OK"], +["''", "HASH256 0x20 0x5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456 EQUAL", "P2SH,STRICTENC", "OK"], +["'a'", "HASH256 0x20 0xbf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8 EQUAL", "P2SH,STRICTENC", "OK"], +["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL", "P2SH,STRICTENC", "OK"], + + +["1","NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC", "OK"], +["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC", "OK"], + +["1", "NOP", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "OK", "Discourage NOPx flag allows OP_NOP"], + +["0", "IF NOP10 ENDIF 1", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "OK", + "Discouraged NOPs are allowed if not executed"], + +["0", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "opcodes above NOP10 invalid if executed"], +["0", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], + +["NOP", +"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", +"P2SH,STRICTENC", "OK", +"520 byte push"], +["1", +"0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"P2SH,STRICTENC", "OK", +"201 opcodes executed. 0x61 is NOP"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"P2SH,STRICTENC", "OK", +"1,000 stack size (0x6f is 3DUP)"], +["1 TOALTSTACK 2 TOALTSTACK 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 2 3 4 5 6 7 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"P2SH,STRICTENC", "OK", +"1,000 stack size (altstack cleared between scriptSig/scriptPubKey)"], +["'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"P2SH,STRICTENC", "OK", +"Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP"], + +["0", +"IF 0x5050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050 ENDIF 1", +"P2SH,STRICTENC", "OK", +">201 opcodes, but RESERVED (0x50) doesn't count towards opcode limit."], + +["NOP","1", "P2SH,STRICTENC", "OK"], + +["1", "0x01 0x01 EQUAL", "P2SH,STRICTENC", "OK", "The following is useful for checking implementations of BN_bn2mpi"], +["127", "0x01 0x7F EQUAL", "P2SH,STRICTENC", "OK"], +["128", "0x02 0x8000 EQUAL", "P2SH,STRICTENC", "OK", "Leave room for the sign bit"], +["32767", "0x02 0xFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["32768", "0x03 0x008000 EQUAL", "P2SH,STRICTENC", "OK"], +["8388607", "0x03 0xFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["8388608", "0x04 0x00008000 EQUAL", "P2SH,STRICTENC", "OK"], +["2147483647", "0x04 0xFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["2147483648", "0x05 0x0000008000 EQUAL", "P2SH,STRICTENC", "OK"], +["549755813887", "0x05 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["549755813888", "0x06 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["9223372036854775807", "0x08 0xFFFFFFFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["-1", "0x01 0x81 EQUAL", "P2SH,STRICTENC", "OK", "Numbers are little-endian with the MSB being a sign bit"], +["-127", "0x01 0xFF EQUAL", "P2SH,STRICTENC", "OK"], +["-128", "0x02 0x8080 EQUAL", "P2SH,STRICTENC", "OK"], +["-32767", "0x02 0xFFFF EQUAL", "P2SH,STRICTENC", "OK"], +["-32768", "0x03 0x008080 EQUAL", "P2SH,STRICTENC", "OK"], +["-8388607", "0x03 0xFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], +["-8388608", "0x04 0x00008080 EQUAL", "P2SH,STRICTENC", "OK"], +["-2147483647", "0x04 0xFFFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], +["-2147483648", "0x05 0x0000008080 EQUAL", "P2SH,STRICTENC", "OK"], +["-4294967295", "0x05 0xFFFFFFFF80 EQUAL", "P2SH,STRICTENC", "OK"], +["-549755813887", "0x05 0xFFFFFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], +["-549755813888", "0x06 0x000000008080 EQUAL", "P2SH,STRICTENC", "OK"], +["-9223372036854775807", "0x08 0xFFFFFFFFFFFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], + +["2147483647", "1ADD 2147483648 EQUAL", "P2SH,STRICTENC", "OK", "We can do math on 4-byte integers, and compare 5-byte ones"], +["2147483647", "1ADD 1", "P2SH,STRICTENC", "OK"], +["-2147483647", "1ADD 1", "P2SH,STRICTENC", "OK"], + +["1", "0x02 0x0100 EQUAL NOT", "P2SH,STRICTENC", "OK", "Not the same byte array..."], +["1", "0x02 0x0100 NUMEQUAL", "P2SH,STRICTENC", "OK", "... but they are numerically equal"], +["11", "0x4c 0x03 0x0b0000 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0", "0x01 0x80 EQUAL NOT", "P2SH,STRICTENC", "OK"], +["0", "0x01 0x80 NUMEQUAL", "P2SH,STRICTENC", "OK", "Zero numerically equals negative zero"], +["0", "0x02 0x0080 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0x03 0x000080", "0x04 0x00000080 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0x03 0x100080", "0x04 0x10000080 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0x03 0x100000", "0x04 0x10000000 NUMEQUAL", "P2SH,STRICTENC", "OK"], + +["NOP", "NOP 1", "P2SH,STRICTENC", "OK", "The following tests check the if(stack.size() < N) tests in each opcode"], +["1", "IF 1 ENDIF", "P2SH,STRICTENC", "OK", "They are here to catch copy-and-paste errors"], +["0", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "OK", "Most of them are duplicated elsewhere,"], +["1", "VERIFY 1", "P2SH,STRICTENC", "OK", "but, hey, more is always better, right?"], + +["0", "TOALTSTACK 1", "P2SH,STRICTENC", "OK"], +["1", "TOALTSTACK FROMALTSTACK", "P2SH,STRICTENC", "OK"], +["0 0", "2DROP 1", "P2SH,STRICTENC", "OK"], +["0 1", "2DUP", "P2SH,STRICTENC", "OK"], +["0 0 1", "3DUP", "P2SH,STRICTENC", "OK"], +["0 1 0 0", "2OVER", "P2SH,STRICTENC", "OK"], +["0 1 0 0 0 0", "2ROT", "P2SH,STRICTENC", "OK"], +["0 1 0 0", "2SWAP", "P2SH,STRICTENC", "OK"], +["1", "IFDUP", "P2SH,STRICTENC", "OK"], +["NOP", "DEPTH 1", "P2SH,STRICTENC", "OK"], +["0", "DROP 1", "P2SH,STRICTENC", "OK"], +["1", "DUP", "P2SH,STRICTENC", "OK"], +["0 1", "NIP", "P2SH,STRICTENC", "OK"], +["1 0", "OVER", "P2SH,STRICTENC", "OK"], +["1 0 0 0 3", "PICK", "P2SH,STRICTENC", "OK"], +["1 0", "PICK", "P2SH,STRICTENC", "OK"], +["1 0 0 0 3", "ROLL", "P2SH,STRICTENC", "OK"], +["1 0", "ROLL", "P2SH,STRICTENC", "OK"], +["1 0 0", "ROT", "P2SH,STRICTENC", "OK"], +["1 0", "SWAP", "P2SH,STRICTENC", "OK"], +["0 1", "TUCK", "P2SH,STRICTENC", "OK"], + +["1", "SIZE", "P2SH,STRICTENC", "OK"], + +["0 0", "EQUAL", "P2SH,STRICTENC", "OK"], +["0 0", "EQUALVERIFY 1", "P2SH,STRICTENC", "OK"], +["0 0 1", "EQUAL EQUAL", "P2SH,STRICTENC", "OK", "OP_0 and bools must have identical byte representations"], + +["0", "1ADD", "P2SH,STRICTENC", "OK"], +["2", "1SUB", "P2SH,STRICTENC", "OK"], +["-1", "NEGATE", "P2SH,STRICTENC", "OK"], +["-1", "ABS", "P2SH,STRICTENC", "OK"], +["0", "NOT", "P2SH,STRICTENC", "OK"], +["-1", "0NOTEQUAL", "P2SH,STRICTENC", "OK"], + +["1 0", "ADD", "P2SH,STRICTENC", "OK"], +["1 0", "SUB", "P2SH,STRICTENC", "OK"], +["-1 -1", "BOOLAND", "P2SH,STRICTENC", "OK"], +["-1 0", "BOOLOR", "P2SH,STRICTENC", "OK"], +["0 0", "NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0 0", "NUMEQUALVERIFY 1", "P2SH,STRICTENC", "OK"], +["-1 0", "NUMNOTEQUAL", "P2SH,STRICTENC", "OK"], +["-1 0", "LESSTHAN", "P2SH,STRICTENC", "OK"], +["1 0", "GREATERTHAN", "P2SH,STRICTENC", "OK"], +["0 0", "LESSTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["0 0", "GREATERTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["-1 0", "MIN", "P2SH,STRICTENC", "OK"], +["1 0", "MAX", "P2SH,STRICTENC", "OK"], +["-1 -1 0", "WITHIN", "P2SH,STRICTENC", "OK"], + +["0", "RIPEMD160", "P2SH,STRICTENC", "OK"], +["0", "SHA1", "P2SH,STRICTENC", "OK"], +["0", "SHA256", "P2SH,STRICTENC", "OK"], +["0", "HASH160", "P2SH,STRICTENC", "OK"], +["0", "HASH256", "P2SH,STRICTENC", "OK"], +["NOP", "CODESEPARATOR 1", "P2SH,STRICTENC", "OK"], + +["NOP", "NOP1 1", "P2SH,STRICTENC", "OK"], +["NOP", "CHECKLOCKTIMEVERIFY 1", "P2SH,STRICTENC", "OK"], +["NOP", "CHECKSEQUENCEVERIFY 1", "P2SH,STRICTENC", "OK"], +["NOP", "NOP4 1", "P2SH,STRICTENC", "OK"], +["NOP", "NOP5 1", "P2SH,STRICTENC", "OK"], +["NOP", "NOP6 1", "P2SH,STRICTENC", "OK"], +["NOP", "NOP7 1", "P2SH,STRICTENC", "OK"], +["NOP", "NOP8 1", "P2SH,STRICTENC", "OK"], +["NOP", "NOP9 1", "P2SH,STRICTENC", "OK"], +["NOP", "NOP10 1", "P2SH,STRICTENC", "OK"], + +["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "CHECKMULTISIG is allowed to have zero keys and/or sigs"], +["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "Zero sigs means no sigs are checked"], +["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], + +["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "CHECKMULTISIG is allowed to have zero keys and/or sigs"], +["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "Zero sigs means no sigs are checked"], +["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], + +["", "0 0 'a' 'b' 2 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "Test from up to 20 pubkeys, all not checked"], +["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 2 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], + +["", +"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", +"P2SH,STRICTENC", "OK", +"nOpCount is incremented by the number of keys evaluated in addition to the usual one op per op. In this case we have zero keys, so we can execute 201 CHECKMULTISIGS"], + +["1", +"0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY", +"P2SH,STRICTENC", "OK"], + +["", +"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", "OK", +"Even though there are no signatures being checked nOpCount is incremented by the number of keys."], + +["1", +"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY", +"P2SH,STRICTENC", "OK"], + +["0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "OK", "Very basic P2SH"], +["0x4c 0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "OK"], + +["0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242", +"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL", +"P2SH,STRICTENC", "OK", +"Basic PUSH signedness check"], + +["0x4c 0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242", +"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL", +"P2SH,STRICTENC", "OK", +"Basic PUSHDATA1 signedness check"], + +["all PUSHDATA forms are equivalent"], + +["0x4c 0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "OK", "PUSHDATA1 of 75 bytes equals direct push of it"], +["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4c 0xFF 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "OK", "PUSHDATA2 of 255 bytes equals PUSHDATA1 of it"], + +["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "OK", "Basic OP_0 execution"], + +["Numeric pushes"], + +["0x01 0x81", "0x4f EQUAL", "", "OK", "OP1_NEGATE pushes 0x81"], +["0x01 0x01", "0x51 EQUAL", "", "OK", "OP_1 pushes 0x01"], +["0x01 0x02", "0x52 EQUAL", "", "OK", "OP_2 pushes 0x02"], +["0x01 0x03", "0x53 EQUAL", "", "OK", "OP_3 pushes 0x03"], +["0x01 0x04", "0x54 EQUAL", "", "OK", "OP_4 pushes 0x04"], +["0x01 0x05", "0x55 EQUAL", "", "OK", "OP_5 pushes 0x05"], +["0x01 0x06", "0x56 EQUAL", "", "OK", "OP_6 pushes 0x06"], +["0x01 0x07", "0x57 EQUAL", "", "OK", "OP_7 pushes 0x07"], +["0x01 0x08", "0x58 EQUAL", "", "OK", "OP_8 pushes 0x08"], +["0x01 0x09", "0x59 EQUAL", "", "OK", "OP_9 pushes 0x09"], +["0x01 0x0a", "0x5a EQUAL", "", "OK", "OP_10 pushes 0x0a"], +["0x01 0x0b", "0x5b EQUAL", "", "OK", "OP_11 pushes 0x0b"], +["0x01 0x0c", "0x5c EQUAL", "", "OK", "OP_12 pushes 0x0c"], +["0x01 0x0d", "0x5d EQUAL", "", "OK", "OP_13 pushes 0x0d"], +["0x01 0x0e", "0x5e EQUAL", "", "OK", "OP_14 pushes 0x0e"], +["0x01 0x0f", "0x5f EQUAL", "", "OK", "OP_15 pushes 0x0f"], +["0x01 0x10", "0x60 EQUAL", "", "OK", "OP_16 pushes 0x10"], + +["Equivalency of different numeric encodings"], + +["0x02 0x8000", "128 NUMEQUAL", "", "OK", "0x8000 equals 128"], +["0x01 0x00", "0 NUMEQUAL", "", "OK", "0x00 numequals 0"], +["0x01 0x80", "0 NUMEQUAL", "", "OK", "0x80 (negative zero) numequals 0"], +["0x02 0x0080", "0 NUMEQUAL", "", "OK", "0x0080 numequals 0"], +["0x02 0x0500", "5 NUMEQUAL", "", "OK", "0x0500 numequals 5"], +["0x03 0xff7f80", "0x02 0xffff NUMEQUAL", "", "OK", ""], +["0x03 0xff7f00", "0x02 0xff7f NUMEQUAL", "", "OK", ""], +["0x04 0xffff7f80", "0x03 0xffffff NUMEQUAL", "", "OK", ""], +["0x04 0xffff7f00", "0x03 0xffff7f NUMEQUAL", "", "OK", ""], + +["Unevaluated non-minimal pushes are ignored"], + +["0 IF 0x4c 0x00 ENDIF 1", "", "MINIMALDATA", "OK", "non-minimal PUSHDATA1 ignored"], +["0 IF 0x4d 0x0000 ENDIF 1", "", "MINIMALDATA", "OK", "non-minimal PUSHDATA2 ignored"], +["0 IF 0x4c 0x00000000 ENDIF 1", "", "MINIMALDATA", "OK", "non-minimal PUSHDATA4 ignored"], +["0 IF 0x01 0x81 ENDIF 1", "", "MINIMALDATA", "OK", "1NEGATE equiv"], +["0 IF 0x01 0x01 ENDIF 1", "", "MINIMALDATA", "OK", "OP_1 equiv"], +["0 IF 0x01 0x02 ENDIF 1", "", "MINIMALDATA", "OK", "OP_2 equiv"], +["0 IF 0x01 0x03 ENDIF 1", "", "MINIMALDATA", "OK", "OP_3 equiv"], +["0 IF 0x01 0x04 ENDIF 1", "", "MINIMALDATA", "OK", "OP_4 equiv"], +["0 IF 0x01 0x05 ENDIF 1", "", "MINIMALDATA", "OK", "OP_5 equiv"], +["0 IF 0x01 0x06 ENDIF 1", "", "MINIMALDATA", "OK", "OP_6 equiv"], +["0 IF 0x01 0x07 ENDIF 1", "", "MINIMALDATA", "OK", "OP_7 equiv"], +["0 IF 0x01 0x08 ENDIF 1", "", "MINIMALDATA", "OK", "OP_8 equiv"], +["0 IF 0x01 0x09 ENDIF 1", "", "MINIMALDATA", "OK", "OP_9 equiv"], +["0 IF 0x01 0x0a ENDIF 1", "", "MINIMALDATA", "OK", "OP_10 equiv"], +["0 IF 0x01 0x0b ENDIF 1", "", "MINIMALDATA", "OK", "OP_11 equiv"], +["0 IF 0x01 0x0c ENDIF 1", "", "MINIMALDATA", "OK", "OP_12 equiv"], +["0 IF 0x01 0x0d ENDIF 1", "", "MINIMALDATA", "OK", "OP_13 equiv"], +["0 IF 0x01 0x0e ENDIF 1", "", "MINIMALDATA", "OK", "OP_14 equiv"], +["0 IF 0x01 0x0f ENDIF 1", "", "MINIMALDATA", "OK", "OP_15 equiv"], +["0 IF 0x01 0x10 ENDIF 1", "", "MINIMALDATA", "OK", "OP_16 equiv"], + +["Numeric minimaldata rules are only applied when a stack item is numerically evaluated; the push itself is allowed"], + +["0x01 0x00", "1", "MINIMALDATA", "OK"], +["0x01 0x80", "1", "MINIMALDATA", "OK"], +["0x02 0x0180", "1", "MINIMALDATA", "OK"], +["0x02 0x0100", "1", "MINIMALDATA", "OK"], +["0x02 0x0200", "1", "MINIMALDATA", "OK"], +["0x02 0x0300", "1", "MINIMALDATA", "OK"], +["0x02 0x0400", "1", "MINIMALDATA", "OK"], +["0x02 0x0500", "1", "MINIMALDATA", "OK"], +["0x02 0x0600", "1", "MINIMALDATA", "OK"], +["0x02 0x0700", "1", "MINIMALDATA", "OK"], +["0x02 0x0800", "1", "MINIMALDATA", "OK"], +["0x02 0x0900", "1", "MINIMALDATA", "OK"], +["0x02 0x0a00", "1", "MINIMALDATA", "OK"], +["0x02 0x0b00", "1", "MINIMALDATA", "OK"], +["0x02 0x0c00", "1", "MINIMALDATA", "OK"], +["0x02 0x0d00", "1", "MINIMALDATA", "OK"], +["0x02 0x0e00", "1", "MINIMALDATA", "OK"], +["0x02 0x0f00", "1", "MINIMALDATA", "OK"], +["0x02 0x1000", "1", "MINIMALDATA", "OK"], + +["Valid version of the 'Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule' script_invalid test"], + +["1 0x02 0x0000", "PICK DROP", "", "OK"], +["1 0x02 0x0000", "ROLL DROP 1", "", "OK"], +["0x02 0x0000", "1ADD DROP 1", "", "OK"], +["0x02 0x0000", "1SUB DROP 1", "", "OK"], +["0x02 0x0000", "NEGATE DROP 1", "", "OK"], +["0x02 0x0000", "ABS DROP 1", "", "OK"], +["0x02 0x0000", "NOT DROP 1", "", "OK"], +["0x02 0x0000", "0NOTEQUAL DROP 1", "", "OK"], + +["0 0x02 0x0000", "ADD DROP 1", "", "OK"], +["0x02 0x0000 0", "ADD DROP 1", "", "OK"], +["0 0x02 0x0000", "SUB DROP 1", "", "OK"], +["0x02 0x0000 0", "SUB DROP 1", "", "OK"], +["0 0x02 0x0000", "BOOLAND DROP 1", "", "OK"], +["0x02 0x0000 0", "BOOLAND DROP 1", "", "OK"], +["0 0x02 0x0000", "BOOLOR DROP 1", "", "OK"], +["0x02 0x0000 0", "BOOLOR DROP 1", "", "OK"], +["0 0x02 0x0000", "NUMEQUAL DROP 1", "", "OK"], +["0x02 0x0000 1", "NUMEQUAL DROP 1", "", "OK"], +["0 0x02 0x0000", "NUMEQUALVERIFY 1", "", "OK"], +["0x02 0x0000 0", "NUMEQUALVERIFY 1", "", "OK"], +["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "", "OK"], +["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "", "OK"], +["0 0x02 0x0000", "LESSTHAN DROP 1", "", "OK"], +["0x02 0x0000 0", "LESSTHAN DROP 1", "", "OK"], +["0 0x02 0x0000", "GREATERTHAN DROP 1", "", "OK"], +["0x02 0x0000 0", "GREATERTHAN DROP 1", "", "OK"], +["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "", "OK"], +["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "", "OK"], +["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "", "OK"], +["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "", "OK"], +["0 0x02 0x0000", "MIN DROP 1", "", "OK"], +["0x02 0x0000 0", "MIN DROP 1", "", "OK"], +["0 0x02 0x0000", "MAX DROP 1", "", "OK"], +["0x02 0x0000 0", "MAX DROP 1", "", "OK"], + +["0x02 0x0000 0 0", "WITHIN DROP 1", "", "OK"], +["0 0x02 0x0000 0", "WITHIN DROP 1", "", "OK"], +["0 0 0x02 0x0000", "WITHIN DROP 1", "", "OK"], + +["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "", "OK"], +["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "", "OK"], +["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "", "OK"], +["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "", "OK"], +["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "", "OK"], + +["While not really correctly DER encoded, the empty signature is allowed by"], +["STRICTENC to provide a compact way to provide a delibrately invalid signature."], +["0", "0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT", "STRICTENC", "OK"], +["0 0", "1 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 1 CHECKMULTISIG NOT", "STRICTENC", "OK"], + +["CHECKMULTISIG evaluation order tests. CHECKMULTISIG evaluates signatures and"], +["pubkeys in a specific order, and will exit early if the number of signatures"], +["left to check is greater than the number of keys left. As STRICTENC fails the"], +["script when it reaches an invalidly encoded signature or pubkey, we can use it"], +["to test the exact order in which signatures and pubkeys are evaluated by"], +["distinguishing CHECKMULTISIG returning false on the stack and the script as a"], +["whole failing."], +["See also the corresponding inverted versions of these tests in script_invalid.json"], +[ + "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501", + "2 0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT", + "STRICTENC", "OK", + "2-of-2 CHECKMULTISIG NOT with the second pubkey invalid, and both signatures validly encoded. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid pubkey." +], +[ + "0 0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501", + "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT", + "STRICTENC", "OK", + "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but second signature invalid. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid signature." +], + +["Increase test coverage for DERSIG"], +["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "", "OK", "Overly long signature is correctly encoded"], +["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "", "OK", "Missing S is correctly encoded"], +["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "S with invalid S length is correctly encoded"], +["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Non-integer R is correctly encoded"], +["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Non-integer S is correctly encoded"], +["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Zero-length R is correctly encoded"], +["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "", "OK", "Zero-length S is correctly encoded for DERSIG"], +["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Negative S is correctly encoded"], + +["2147483648", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "OK", "CSV passes if stack top bit 1 << 31 is set"], + +["", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE", "Test the test: we should have an empty stack after scriptSig evaluation"], +[" ", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE", "and multiple spaces should not change that."], +[" ", "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","BAD_OPCODE", "PUSHDATA1 with not enough bytes"], +["0x4d0200ff","0x01 NOP", "P2SH,STRICTENC","BAD_OPCODE", "PUSHDATA2 with not enough bytes"], +["0x4e03000000ffff","0x01 NOP", "P2SH,STRICTENC","BAD_OPCODE", "PUSHDATA4 with not enough bytes"], + +["1", "IF 0x50 ENDIF 1", "P2SH,STRICTENC","BAD_OPCODE", "0x50 is reserved"], +["0x52", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC","EVAL_FALSE", "0x51 through 0x60 push 1 through 16 onto stack"], +["0","NOP", "P2SH,STRICTENC","EVAL_FALSE",""], +["1", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "VER non-functional"], +["0", "IF VERIF ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "VERIF illegal everywhere"], +["0", "IF ELSE 1 ELSE VERIF ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "VERIF illegal everywhere"], +["0", "IF VERNOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "VERNOTIF illegal everywhere"], +["0", "IF ELSE 1 ELSE VERNOTIF ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "VERNOTIF illegal everywhere"], + +["1 IF", "1 ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "IF/ENDIF can't span scriptSig/scriptPubKey"], +["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", "OP_RETURN", "Multiple ELSEs"], +["1", "IF 1 ELSE ELSE RETURN ENDIF", "P2SH,STRICTENC", "OP_RETURN"], + +["1", "ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "Malformed IF/ELSE/ENDIF sequence"], +["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", "OP_RETURN", "canonical prunable txout format"], +["0 IF", "RETURN ENDIF 1", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey"], + +["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", "INVALID_ALTSTACK_OPERATION", "alt stack not shared between sig/pubkey"], + +["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", "DISABLED_OPCODE", "CAT disabled"], +["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "CAT disabled"], +["'abc' 1 1", "SUBSTR", "P2SH,STRICTENC", "DISABLED_OPCODE", "SUBSTR disabled"], +["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "SUBSTR disabled"], +["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "LEFT disabled"], +["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "RIGHT disabled"], + +["NOP", "SIZE 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], + +["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "INVERT disabled"], +["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "AND disabled"], +["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "OR disabled"], +["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "XOR disabled"], +["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "2MUL disabled"], +["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "2DIV disabled"], +["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "MUL disabled"], +["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "DIV disabled"], +["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "MOD disabled"], +["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "LSHIFT disabled"], +["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "RSHIFT disabled"], + +["", "EQUAL NOT", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "EQUAL must error when there are no stack items"], +["0", "EQUAL NOT", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "EQUAL must error when there are not 2 stack items"], +["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", "UNKNOWN_ERROR", "arithmetic operands must be in range [-2^31...2^31] "], +["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "UNKNOWN_ERROR", "arithmetic operands must be in range [-2^31...2^31] "], +["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "UNKNOWN_ERROR", "NUMEQUAL must be in numeric range"], +["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "UNKNOWN_ERROR", "NOT is an arithmetic operand"], + +["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], +["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], +["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], +["2 2DIV", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], +["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], +["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], +["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], + +["1", "NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], +["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY 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", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "CHECKLOCKTIMEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "CHECKSEQUENCEVERIFY", "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", "DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in scriptSig"], + +["1 0x01 0xb9", "HASH160 0x14 0x15727299b05b45fdaf9ac9ecf7565cfe27c3e567 EQUAL", + "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript"], + +["0x50","1", "P2SH,STRICTENC", "BAD_OPCODE", "opcode 0x50 is reserved"], +["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "opcodes above NOP10 invalid if executed"], +["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", "UNBALANCED_CONDITIONAL", "invalid because scriptSig and scriptPubKey are processed separately"], + +["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", +"PUSH_SIZE", +">520 byte push"], +["0", +"IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1", +"P2SH,STRICTENC", +"PUSH_SIZE", +">520 byte push in non-executed IF branch"], +["1", +"0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"P2SH,STRICTENC", +"OP_COUNT", +">201 opcodes executed. 0x61 is NOP"], +["0", +"IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1", +"P2SH,STRICTENC", +"OP_COUNT", +">201 opcodes including non-executed IF branch. 0x61 is NOP"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"P2SH,STRICTENC", +"STACK_SIZE", +">1,000 stack size (0x6f is 3DUP)"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"P2SH,STRICTENC", +"STACK_SIZE", +">1,000 stack+altstack 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", +"SCRIPT_SIZE", +"10,001-byte scriptPubKey"], + +["NOP1","NOP10", "P2SH,STRICTENC", "EVAL_FALSE"], + +["1","VER", "P2SH,STRICTENC", "BAD_OPCODE", "OP_VER is reserved"], +["1","VERIF", "P2SH,STRICTENC", "BAD_OPCODE", "OP_VERIF is reserved"], +["1","VERNOTIF", "P2SH,STRICTENC", "BAD_OPCODE", "OP_VERNOTIF is reserved"], +["1","RESERVED", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED is reserved"], +["1","RESERVED1", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED1 is reserved"], +["1","RESERVED2", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED2 is reserved"], +["1","0xba", "P2SH,STRICTENC", "BAD_OPCODE", "0xba == OP_NOP10 + 1"], + +["2147483648", "1ADD 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"], +["2147483648", "NEGATE 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"], +["-2147483648", "1ADD 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "Because we use a sign bit, -2147483648 is also 5 bytes"], +["2147483647", "1ADD 1SUB 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], +["2147483648", "1SUB 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], + +["2147483648 1", "BOOLOR 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)"], +["2147483648 1", "BOOLAND 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do BOOLAND on 5-byte integers"], + +["1", "1 ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "ENDIF without IF"], +["1", "IF 1", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "IF without ENDIF"], +["1 IF 1", "ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "IFs don't carry over"], + +["NOP", "IF 1 ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "The following tests check the if(stack.size() < N) tests in each opcode"], +["NOP", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "They are here to catch copy-and-paste errors"], +["NOP", "VERIFY 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "Most of them are duplicated elsewhere,"], + +["NOP", "TOALTSTACK 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "but, hey, more is always better, right?"], +["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", "INVALID_STACK_OPERATION", "CHECKSIG must error when there are no stack items"], +["0", "CHECKSIG NOT", "STRICTENC", "INVALID_STACK_OPERATION", "CHECKSIG must error when there are not 2 stack items"], +["", "CHECKMULTISIG NOT", "STRICTENC", "INVALID_STACK_OPERATION", "CHECKMULTISIG must error when there are no stack items"], +["", "-1 CHECKMULTISIG NOT", "STRICTENC", "PUBKEY_COUNT", "CHECKMULTISIG must error when the specified number of pubkeys is negative"], +["", "1 CHECKMULTISIG NOT", "STRICTENC", "INVALID_STACK_OPERATION", "CHECKMULTISIG must error when there are not enough pubkeys on the stack"], +["", "-1 0 CHECKMULTISIG NOT", "STRICTENC", "SIG_COUNT", "CHECKMULTISIG must error when the specified number of signatures is negative"], +["", "1 'pk1' 1 CHECKMULTISIG NOT", "STRICTENC", "INVALID_STACK_OPERATION", "CHECKMULTISIG must error when there are not enough signatures on the stack"], +["", "'dummy' 'sig1' 1 'pk1' 1 CHECKMULTISIG IF 1 ENDIF", "", "EVAL_FALSE", "CHECKMULTISIG must push false to stack when signature is invalid when NOT in strict enc mode"], + +["", +"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", +"OP_COUNT", +"202 CHECKMULTISIGS, fails due to 201 op limit"], + +["1", +"0 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY", +"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", +"OP_COUNT", +"Fails due to 201 sig op limit"], + +["1", +"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY", +"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", "PUBKEY_COUNT", "nPubKeys > 20"], +["0 'sig' 1 0", "CHECKMULTISIG 1", "P2SH,STRICTENC", "SIG_COUNT", "nSigs > nPubKeys"], + + +["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "SIG_PUSHONLY", "Tests for Script.IsPushOnly()"], +["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "SIG_PUSHONLY"], + +["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED in P2SH should fail"], +["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "P2SH,STRICTENC", "BAD_OPCODE", "OP_VER in P2SH should fail"], + +["0x00", "'00' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE", "Basic OP_0 execution"], + +["MINIMALDATA enforcement for PUSHDATAs"], + +["0x4c 0x00", "DROP 1", "MINIMALDATA", "MINIMALDATA", "Empty vector minimally represented by OP_0"], +["0x01 0x81", "DROP 1", "MINIMALDATA", "MINIMALDATA", "-1 minimally represented by OP_1NEGATE"], +["0x01 0x01", "DROP 1", "MINIMALDATA", "MINIMALDATA", "1 to 16 minimally represented by OP_1 to OP_16"], +["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", + "MINIMALDATA", + "PUSHDATA1 of 72 bytes minimally represented by direct push"], + +["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", + "MINIMALDATA", + "PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1"], + +["0x4e 0x00010000 0x11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", + "MINIMALDATA", + "PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2"], + +["MINIMALDATA enforcement for numeric arguments"], + +["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 0"], +["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 0"], +["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "0x80 (negative zero) numequals 0"], +["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 0"], +["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 5"], +["0x03 0x050000", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 5"], +["0x02 0x0580", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals -5"], +["0x03 0x050080", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals -5"], +["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "Minimal encoding is 0xffff"], +["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "Minimal encoding is 0xff7f"], +["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "Minimal encoding is 0xffffff"], +["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "Minimal encoding is 0xffff7f"], + +["Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule"], + +["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"], +["pubkeys/signatures so they fail due to the STRICTENC rules on validly encoded"], +["signatures and pubkeys."], +[ + "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501", + "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0 2 CHECKMULTISIG NOT", + "STRICTENC", + "PUBKEYTYPE", + "2-of-2 CHECKMULTISIG NOT with the first pubkey invalid, and both signatures validly encoded." +], +[ + "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 1", + "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT", + "STRICTENC", + "SIG_DER", + "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid." +], +[ + "0 0x47 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f01 0x46 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f", + "2 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 3 CHECKMULTISIG", + "P2SH,STRICTENC", + "SIG_DER", + "2-of-3 with one valid and one invalid signature due to parse error, nSigs > validSigs" +], + +["Increase DERSIG test coverage"], +["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Overly long signature is incorrectly encoded for DERSIG"], +["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Missing S is incorrectly encoded for DERSIG"], +["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "S with invalid S length is incorrectly encoded for DERSIG"], +["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Non-integer R is incorrectly encoded for DERSIG"], +["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Non-integer S is incorrectly encoded for DERSIG"], +["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Zero-length R is incorrectly encoded for DERSIG"], +["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Zero-length S is incorrectly encoded for DERSIG"], +["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Negative S is incorrectly encoded for DERSIG"], + +["Automatically generated test cases"], +[ + "0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "", + "OK", + "P2PK" +], +[ + "0x47 0x304402200a5c6163f07b8c3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "", + "EVAL_FALSE", + "P2PK, bad sig" +], +[ + "0x47 0x304402206e05a6fe23c59196ffe176c9ddc31e73a9885638f9d1328d47c0c703863b8876022076feb53811aa5b04e0e79f938eb19906cc5e67548bc555a8e8b8b0fc603d840c01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", + "DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG", + "", + "OK", + "P2PKH" +], +[ + "0x47 0x3044022034bb0494b50b8ef130e2185bb220265b9284ef5b4b8a8da4d8415df489c83b5102206259a26d9cc0a125ac26af6153b17c02956855ebe1467412f066e402f5f05d1201 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", + "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG", + "", + "EQUALVERIFY", + "P2PKH, bad pubkey" +], +[ + "0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790281", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", + "", + "OK", + "P2PK anyonecanpay" +], +[ + "0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790201", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", + "", + "EVAL_FALSE", + "P2PK anyonecanpay marked with normal hashtype" +], +[ + "0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", + "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", + "P2SH", + "OK", + "P2SH(P2PK)" +], +[ + "0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", + "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", + "P2SH", + "EVAL_FALSE", + "P2SH(P2PK), bad redeemscript" +], +[ + "0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", + "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", + "", + "OK", + "P2SH(P2PKH), bad sig but no VERIFY_P2SH" +], +[ + "0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", + "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", + "P2SH", + "EQUALVERIFY", + "P2SH(P2PKH), bad sig" +], +[ + "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", + "", + "OK", + "3-of-3" +], +[ + "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", + "", + "EVAL_FALSE", + "3-of-3, 2 sigs" +], +[ + "0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0x47 0x30440220563e5b3b1fc11662a84bc5ea2a32cc3819703254060ba30d639a1aaf2d5068ad0220601c1f47ddc76d93284dd9ed68f7c9974c4a0ea7cbe8a247d6bc3878567a5fca01 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", + "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", + "P2SH", + "OK", + "P2SH(2-of-3)" +], +[ + "0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", + "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", + "P2SH", + "EVAL_FALSE", + "P2SH(2-of-3), 1 sig" +], +[ + "0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "OK", + "P2PK with too much R padding but no DERSIG" +], +[ + "0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "DERSIG", + "SIG_DER", + "P2PK with too much R padding" +], +[ + "0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "OK", + "P2PK with too much S padding but no DERSIG" +], +[ + "0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "DERSIG", + "SIG_DER", + "P2PK with too much S padding" +], +[ + "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "OK", + "P2PK with too little R padding but no DERSIG" +], +[ + "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "DERSIG", + "SIG_DER", + "P2PK with too little R padding" +], +[ + "0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", + "", + "OK", + "P2PK NOT with bad sig with too much R padding but no DERSIG" +], +[ + "0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", + "DERSIG", + "SIG_DER", + "P2PK NOT with bad sig with too much R padding" +], +[ + "0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", + "", + "EVAL_FALSE", + "P2PK NOT with too much R padding but no DERSIG" +], +[ + "0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", + "DERSIG", + "SIG_DER", + "P2PK NOT with too much R padding" +], +[ + "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "OK", + "BIP66 example 1, without DERSIG" +], +[ + "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "DERSIG", + "SIG_DER", + "BIP66 example 1, with DERSIG" +], +[ + "0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "", + "EVAL_FALSE", + "BIP66 example 2, without DERSIG" +], +[ + "0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "DERSIG", + "SIG_DER", + "BIP66 example 2, with DERSIG" +], +[ + "0", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "EVAL_FALSE", + "BIP66 example 3, without DERSIG" +], +[ + "0", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "DERSIG", + "EVAL_FALSE", + "BIP66 example 3, with DERSIG" +], +[ + "0", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "", + "OK", + "BIP66 example 4, without DERSIG" +], +[ + "0", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "DERSIG", + "OK", + "BIP66 example 4, with DERSIG" +], +[ + "0x09 0x300602010102010101", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "DERSIG", + "OK", + "BIP66 example 4, with DERSIG, non-null DER-compliant signature" +], +[ + "0", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "DERSIG,NULLFAIL", + "OK", + "BIP66 example 4, with DERSIG and NULLFAIL" +], +[ + "0x09 0x300602010102010101", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "DERSIG,NULLFAIL", + "NULLFAIL", + "BIP66 example 4, with DERSIG and NULLFAIL, non-null DER-compliant signature" +], +[ + "1", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "EVAL_FALSE", + "BIP66 example 5, without DERSIG" +], +[ + "1", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "DERSIG", + "SIG_DER", + "BIP66 example 5, with DERSIG" +], +[ + "1", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "", + "OK", + "BIP66 example 6, without DERSIG" +], +[ + "1", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "DERSIG", + "SIG_DER", + "BIP66 example 6, with DERSIG" +], +[ + "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", + "", + "OK", + "BIP66 example 7, without DERSIG" +], +[ + "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", + "DERSIG", + "SIG_DER", + "BIP66 example 7, with DERSIG" +], +[ + "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", + "", + "EVAL_FALSE", + "BIP66 example 8, without DERSIG" +], +[ + "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", + "DERSIG", + "SIG_DER", + "BIP66 example 8, with DERSIG" +], +[ + "0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", + "", + "EVAL_FALSE", + "BIP66 example 9, without DERSIG" +], +[ + "0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", + "DERSIG", + "SIG_DER", + "BIP66 example 9, with DERSIG" +], +[ + "0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", + "", + "OK", + "BIP66 example 10, without DERSIG" +], +[ + "0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", + "DERSIG", + "SIG_DER", + "BIP66 example 10, with DERSIG" +], +[ + "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", + "", + "EVAL_FALSE", + "BIP66 example 11, without DERSIG" +], +[ + "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", + "DERSIG", + "EVAL_FALSE", + "BIP66 example 11, with DERSIG" +], +[ + "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", + "", + "OK", + "BIP66 example 12, without DERSIG" +], +[ + "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", + "DERSIG", + "OK", + "BIP66 example 12, with DERSIG" +], +[ + "0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "", + "OK", + "P2PK with multi-byte hashtype, without DERSIG" +], +[ + "0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "DERSIG", + "SIG_DER", + "P2PK with multi-byte hashtype, with DERSIG" +], +[ + "0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "", + "OK", + "P2PK with high S but no LOW_S" +], +[ + "0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "LOW_S", + "SIG_HIGH_S", + "P2PK with high S" +], +[ + "0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "", + "OK", + "P2PK with hybrid pubkey but no STRICTENC" +], +[ + "0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "STRICTENC", + "PUBKEYTYPE", + "P2PK with hybrid pubkey" +], +[ + "0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", + "", + "EVAL_FALSE", + "P2PK NOT with hybrid pubkey but no STRICTENC" +], +[ + "0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", + "STRICTENC", + "PUBKEYTYPE", + "P2PK NOT with hybrid pubkey" +], +[ + "0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", + "", + "OK", + "P2PK NOT with invalid hybrid pubkey but no STRICTENC" +], +[ + "0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", + "STRICTENC", + "PUBKEYTYPE", + "P2PK NOT with invalid hybrid pubkey" +], +[ + "0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401", + "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "", + "OK", + "1-of-2 with the second 1 hybrid pubkey and no STRICTENC" +], +[ + "0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401", + "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "STRICTENC", + "OK", + "1-of-2 with the second 1 hybrid pubkey" +], +[ + "0 0x47 0x3044022079c7824d6c868e0e1a273484e28c2654a27d043c8a27f49f52cb72efed0759090220452bbbf7089574fa082095a4fc1b3a16bafcf97a3a34d745fafc922cce66b27201", + "1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG", + "STRICTENC", + "PUBKEYTYPE", + "1-of-2 with the first 1 hybrid pubkey" +], +[ + "0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", + "", + "OK", + "P2PK with undefined hashtype but no STRICTENC" +], +[ + "0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", + "STRICTENC", + "SIG_HASHTYPE", + "P2PK with undefined hashtype" +], +[ + "0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT", + "", + "OK", + "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC" +], +[ + "0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT", + "STRICTENC", + "SIG_HASHTYPE", + "P2PK NOT with invalid sig and undefined hashtype" +], +[ + "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", + "", + "OK", + "3-of-3 with nonzero dummy but no NULLDUMMY" +], +[ + "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", + "NULLDUMMY", + "SIG_NULLDUMMY", + "3-of-3 with nonzero dummy" +], +[ + "1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT", + "", + "OK", + "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY" +], +[ + "1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT", + "NULLDUMMY", + "SIG_NULLDUMMY", + "3-of-3 NOT with invalid sig with nonzero dummy" +], +[ + "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "", + "OK", + "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY" +], +[ + "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "SIGPUSHONLY", + "SIG_PUSHONLY", + "2-of-2 with two identical keys and sigs pushed using OP_DUP" +], +[ + "0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP8 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", + "HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL", + "", + "OK", + "P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY" +], +[ + "0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 NOP8", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "", + "OK", + "P2PK with non-push scriptSig but with P2SH validation" +], +[ + "0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP8 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", + "HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL", + "P2SH", + "SIG_PUSHONLY", + "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY" +], +[ + "0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP8 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", + "HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL", + "SIGPUSHONLY", + "SIG_PUSHONLY", + "P2SH(P2PK) with non-push scriptSig but not P2SH" +], +[ + "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "SIGPUSHONLY", + "OK", + "2-of-2 with two identical keys and sigs pushed" +], +[ + "11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "P2SH", + "OK", + "P2PK with unnecessary input but no CLEANSTACK" +], +[ + "11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "CLEANSTACK,P2SH", + "CLEANSTACK", + "P2PK with unnecessary input" +], +[ + "11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", + "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", + "P2SH", + "OK", + "P2SH with unnecessary input but no CLEANSTACK" +], +[ + "11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", + "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", + "CLEANSTACK,P2SH", + "CLEANSTACK", + "P2SH with unnecessary input" +], +[ + "0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", + "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", + "CLEANSTACK,P2SH", + "OK", + "P2SH with CLEANSTACK" +], +[ + [ + 123450.00000000 + ], + "0x47 0x30440220368d68340dfbebf99d5ec87d77fba899763e466c0a7ab2fa0221fb868ab0f3ef0220266c1a52a8e5b7b597613b80cf53814d3925dfb6715dce712c8e7a25e63a044041", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "SIGHASH_FORKID", + "OK", + "P2PK FORKID" +], +[ + [ + 123450.00000000 + ], + "0x47 0x3044022053cebf0befa1f435d1631d7b0de2c870203b4cedcce98bd2ce6b72e08978e1a302203b63345ec2de3682eec5f008a3b1c925b2f71be53f0469a49fb7f1df0c49409b41", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "SIGHASH_FORKID", + "EVAL_FALSE", + "P2PK INVALID AMOUNT" +], +[ + [ + 123450.00000000 + ], + "0x47 0x30440220368d68340dfbebf99d5ec87d77fba899763e466c0a7ab2fa0221fb868ab0f3ef0220266c1a52a8e5b7b597613b80cf53814d3925dfb6715dce712c8e7a25e63a044041", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "", + "EVAL_FALSE", + "P2PK INVALID FORKID" +], + +["CHECKSEQUENCEVERIFY tests"], +["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a empty stack"], +["-1", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "NEGATIVE_LOCKTIME", "CSV automatically fails if stack top is negative"], +["0x0100", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY,MINIMALDATA", "UNKNOWN_ERROR", "CSV fails if stack top is not minimally encoded"], +["0", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is set and the tx version < 2"], +["4294967296", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"], + +["SIGHASH_FORKID"], +["0x01 0x40", "0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT", "", "OK"], +["0x01 0x40", "0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT", "SIGHASH_FORKID", "OK"], +["0 0x01 0x40", "1 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 1 CHECKMULTISIG NOT", "", "OK"], +["0 0x01 0x40", "1 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 1 CHECKMULTISIG NOT", "SIGHASH_FORKID", "OK"], + +["NULLFAIL should cover all signatures and signatures only"], +["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG", "OK", "BIP66 and NULLFAIL-compliant"], +["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "OK", "BIP66 and NULLFAIL-compliant"], +["1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "OK", "BIP66 and NULLFAIL-compliant, not NULLDUMMY-compliant"], +["1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL,NULLDUMMY", "SIG_NULLDUMMY", "BIP66 and NULLFAIL-compliant, not NULLDUMMY-compliant"], +["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG", "OK", "BIP66-compliant but not NULLFAIL-compliant"], +["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "NULLFAIL", "BIP66-compliant but not NULLFAIL-compliant"], +["0 0x09 0x300602010102010101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG", "OK", "BIP66-compliant but not NULLFAIL-compliant"], +["0 0x09 0x300602010102010101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "NULLFAIL", "BIP66-compliant but not NULLFAIL-compliant"], + +["The End"] +] diff --git a/src/test/data/sighash.json b/src/test/data/sighash.json new file mode 100644 index 00000000..d5d1dd5b --- /dev/null +++ b/src/test/data/sighash.json @@ -0,0 +1,1004 @@ +[ + ["raw_transaction, script, input_index, hashType, signature_hash (result)"], + ["907c2bc503ade11cc3b04eb2918b6f547b0630ab569273824748c87ea14b0696526c66ba740200000004ab65ababfd1f9bdd4ef073c7afc4ae00da8a66f429c917a0081ad1e1dabce28d373eab81d8628de802000000096aab5253ab52000052ad042b5f25efb33beec9f3364e8a9139e8439d9d7e26529c3c30b6c3fd89f8684cfd68ea0200000009ab53526500636a52ab599ac2fe02a526ed040000000008535300516352515164370e010000000003006300ab2ec229", "", 2, 1864164639, "31af167a6cf3f9d5f6875caa4d31704ceb0eba078d132b78dab52c3b8997317e"], + ["a0aa3126041621a6dea5b800141aa696daf28408959dfb2df96095db9fa425ad3f427f2f6103000000015360290e9c6063fa26912c2e7fb6a0ad80f1c5fea1771d42f12976092e7a85a4229fdb6e890000000001abc109f6e47688ac0e4682988785744602b8c87228fcef0695085edf19088af1a9db126e93000000000665516aac536affffffff8fe53e0806e12dfd05d67ac68f4768fdbe23fc48ace22a5aa8ba04c96d58e2750300000009ac51abac63ab5153650524aa680455ce7b000000000000499e50030000000008636a00ac526563ac5051ee030000000003abacabd2b6fe000000000003516563910fb6b5", "65", 0, -1391424484, "48d6a1bd2cd9eec54eb866fc71209418a950402b5d7e52363bfb75c98e141175"], + ["6e7e9d4b04ce17afa1e8546b627bb8d89a6a7fefd9d892ec8a192d79c2ceafc01694a6a7e7030000000953ac6a51006353636a33bced1544f797f08ceed02f108da22cd24c9e7809a446c61eb3895914508ac91f07053a01000000055163ab516affffffff11dc54eee8f9e4ff0bcf6b1a1a35b1cd10d63389571375501af7444073bcec3c02000000046aab53514a821f0ce3956e235f71e4c69d91abe1e93fb703bd33039ac567249ed339bf0ba0883ef300000000090063ab65000065ac654bec3cc504bcf499020000000005ab6a52abac64eb060100000000076a6a5351650053bbbc130100000000056a6aab53abd6e1380100000000026a51c4e509b8", "acab655151", 0, 479279909, "2a3d95b09237b72034b23f2d2bb29fa32a58ab5c6aa72f6aafdfa178ab1dd01c"], + ["73107cbd025c22ebc8c3e0a47b2a760739216a528de8d4dab5d45cbeb3051cebae73b01ca10200000007ab6353656a636affffffffe26816dffc670841e6a6c8c61c586da401df1261a330a6c6b3dd9f9a0789bc9e000000000800ac6552ac6aac51ffffffff0174a8f0010000000004ac52515100000000", "5163ac63635151ac", 1, 1190874281, "b8ab92fe16927c86508abb81c786d4b82dc9c895d3e7db8631fad2296f6a7d9b"], + ["e93bbf6902be872933cb987fc26ba0f914fcfc2f6ce555258554dd9939d12032a8536c8802030000000453ac5353eabb6451e074e6fef9de211347d6a45900ea5aaf2636ef7967f565dce66fa451805c5cd10000000003525253ffffffff047dc3e6020000000007516565ac656aabec9eea010000000001633e46e600000000000015080a030000000001ab00000000", "5300ac6a53ab6a", 1, -886562767, "f03aa4fc5f97e826323d0daa03343ebf8a34ed67a1ce18631f8b88e5c992e798"], + ["50818f4c01b464538b1e7e7f5ae4ed96ad23c68c830e78da9a845bc19b5c3b0b20bb82e5e9030000000763526a63655352ffffffff023b3f9c040000000008630051516a6a5163a83caf01000000000553ab65510000000000", "6aac", 0, 946795545, "746306f322de2b4b58ffe7faae83f6a72433c22f88062cdde881d4dd8a5a4e2d"], + ["a93e93440250f97012d466a6cc24839f572def241c814fe6ae94442cf58ea33eb0fdd9bcc1030000000600636a0065acffffffff5dee3a6e7e5ad6310dea3e5b3ddda1a56bf8de7d3b75889fc024b5e233ec10f80300000007ac53635253ab53ffffffff0160468b04000000000800526a5300ac526a00000000", "ac00636a53", 1, 1773442456, "c0fc6eafaf407ef6670526b133ec492802cb609a3491baaf79619097666471d4"], + ["ce7d371f0476dda8b811d4bf3b64d5f86204725deeaa3937861869d5b2766ea7d17c57e40b0100000003535265ffffffff7e7e9188f76c34a46d0bbe856bde5cb32f089a07a70ea96e15e92abb37e479a10100000006ab6552ab655225bcab06d1c2896709f364b1e372814d842c9c671356a1aa5ca4e060462c65ae55acc02d0000000006abac0063ac5281b33e332f96beebdbc6a379ebe6aea36af115c067461eb99d22ba1afbf59462b59ae0bd0200000004ab635365be15c23801724a1704000000000965006a65ac00000052ca555572", "53ab530051ab", 1, 2030598449, "c336b2f7d3702fbbdeffc014d106c69e3413c7c71e436ba7562d8a7a2871f181"], + ["d3b7421e011f4de0f1cea9ba7458bf3486bee722519efab711a963fa8c100970cf7488b7bb0200000003525352dcd61b300148be5d05000000000000000000", "535251536aac536a", 0, -1960128125, "29aa6d2d752d3310eba20442770ad345b7f6a35f96161ede5f07b33e92053e2a"], + ["04bac8c5033460235919a9c63c42b2db884c7c8f2ed8fcd69ff683a0a2cccd9796346a04050200000003655351fcad3a2c5a7cbadeb4ec7acc9836c3f5c3e776e5c566220f7f965cf194f8ef98efb5e3530200000007526a006552526526a2f55ba5f69699ece76692552b399ba908301907c5763d28a15b08581b23179cb01eac03000000075363ab6a516351073942c2025aa98a05000000000765006aabac65abd7ffa6030000000004516a655200000000", "53ac6365ac526a", 1, 764174870, "bf5fdc314ded2372a0ad078568d76c5064bf2affbde0764c335009e56634481b"], + ["c363a70c01ab174230bbe4afe0c3efa2d7f2feaf179431359adedccf30d1f69efe0c86ed390200000002ab51558648fe0231318b04000000000151662170000000000008ac5300006a63acac00000000", "", 0, 2146479410, "191ab180b0d753763671717d051f138d4866b7cb0d1d4811472e64de595d2c70"], + ["8d437a7304d8772210a923fd81187c425fc28c17a5052571501db05c7e89b11448b36618cd02000000026a6340fec14ad2c9298fde1477f1e8325e5747b61b7e2ff2a549f3d132689560ab6c45dd43c3010000000963ac00ac000051516a447ed907a7efffebeb103988bf5f947fc688aab2c6a7914f48238cf92c337fad4a79348102000000085352ac526a5152517436edf2d80e3ef06725227c970a816b25d0b58d2cd3c187a7af2cea66d6b27ba69bf33a0300000007000063ab526553f3f0d6140386815d030000000003ab6300de138f00000000000900525153515265abac1f87040300000000036aac6500000000", "51", 3, -315779667, "b6632ac53578a741ae8c36d8b69e79f39b89913a2c781cdf1bf47a8c29d997a5"], + ["fd878840031e82fdbe1ad1d745d1185622b0060ac56638290ec4f66b1beef4450817114a2c0000000009516a63ab53650051abffffffff37b7a10322b5418bfd64fb09cd8a27ddf57731aeb1f1f920ffde7cb2dfb6cdb70300000008536a5365ac53515369ecc034f1594690dbe189094dc816d6d57ea75917de764cbf8eccce4632cbabe7e116cd0100000003515352ffffffff035777fc000000000003515200abe9140300000000050063005165bed6d10200000000076300536363ab65195e9110", "635265", 0, 1729787658, "6e3735d37a4b28c45919543aabcb732e7a3e1874db5315abb7cc6b143d62ff10"], + ["f40a750702af06efff3ea68e5d56e42bc41cdb8b6065c98f1221fe04a325a898cb61f3d7ee030000000363acacffffffffb5788174aef79788716f96af779d7959147a0c2e0e5bfb6c2dba2df5b4b97894030000000965510065535163ac6affffffff0445e6fd0200000000096aac536365526a526aa6546b000000000008acab656a6552535141a0fd010000000000c897ea030000000008526500ab526a6a631b39dba3", "00abab5163ac", 1, -1778064747, "d76d0fc0abfa72d646df888bce08db957e627f72962647016eeae5a8412354cf"], + ["a63bc673049c75211aa2c09ecc38e360eaa571435fedd2af1116b5c1fa3d0629c269ecccbf0000000008ac65ab516352ac52ffffffffbf1a76fdda7f451a5f0baff0f9ccd0fe9136444c094bb8c544b1af0fa2774b06010000000463535253ffffffff13d6b7c3ddceef255d680d87181e100864eeb11a5bb6a3528cb0d70d7ee2bbbc02000000056a0052abab951241809623313b198bb520645c15ec96bfcc74a2b0f3db7ad61d455cc32db04afc5cc702000000016309c9ae25014d9473020000000004abab6aac3bb1e803", "", 3, -232881782, "e8421993748334c01413fa3339d0d9506e9e6074f4b5a1ccb48e454553b7daa7"], + ["4c565efe04e7d32bac03ae358d63140c1cfe95de15e30c5b84f31bb0b65bb542d637f49e0f010000000551abab536348ae32b31c7d3132030a510a1b1aacf7b7c3f19ce8dc49944ef93e5fa5fe2d356b4a73a00100000009abac635163ac00ab514c8bc57b6b844e04555c0a4f4fb426df139475cd2396ae418bc7015820e852f711519bc202000000086a00510000abac52488ff4aec72cbcfcc98759c58e20a8d2d9725aa4a80f83964e69bc4e793a4ff25cd75dc701000000086a52ac6aac5351532ec6b10802463e0200000000000553005265523e08680100000000002f39a6b0", "", 3, 70712720, "0763d11d139ecf89e0e21c7e0ae949b4e8c50b545a61c7b84676875c4dddccfc"], + ["1233d5e703403b3b8b4dae84510ddfc126b4838dcb47d3b23df815c0b3a07b55bf3098110e010000000163c5c55528041f480f40cf68a8762d6ed3efe2bd402795d5233e5d94bf5ddee71665144898030000000965525165655151656affffffff6381667e78bb74d0880625993bec0ea3bd41396f2bcccc3cc097b240e5e92d6a01000000096363acac6a63536365ffffffff04610ad60200000000065251ab65ab52e90d680200000000046351516ae30e98010000000008abab52520063656a671856010000000004ac6aac514c84e383", "6aabab636300", 1, -114996813, "aeb8c5a62e8a0b572c28f2029db32854c0b614dbecef0eaa726abebb42eebb8d"], + ["0c69702103b25ceaed43122cc2672de84a3b9aa49872f2a5bb458e19a52f8cc75973abb9f102000000055365656aacffffffff3ffb1cf0f76d9e3397de0942038c856b0ebbea355dc9d8f2b06036e19044b0450100000000ffffffff4b7793f4169617c54b734f2cd905ed65f1ce3d396ecd15b6c426a677186ca0620200000008655263526551006a181a25b703240cce0100000000046352ab53dee22903000000000865526a6a516a51005e121602000000000852ab52ababac655200000000", "6a516aab63", 1, -2040012771, "a6e6cb69f409ec14e10dd476f39167c29e586e99bfac93a37ed2c230fcc1dbbe"], + ["fd22692802db8ae6ab095aeae3867305a954278f7c076c542f0344b2591789e7e33e4d29f4020000000151ffffffffb9409129cfed9d3226f3b6bab7a2c83f99f48d039100eeb5796f00903b0e5e5e0100000006656552ac63abd226abac0403e649000000000007abab51ac5100ac8035f10000000000095165006a63526a52510d42db030000000007635365ac6a63ab24ef5901000000000453ab6a0000000000", "536a52516aac6a", 1, 309309104, "5927e4991864dbe2f8e44d7a5e902757dc51bee7266b3bee0af926c7d285b986"], + ["a43f85f701ffa54a3cc57177510f3ea28ecb6db0d4431fc79171cad708a6054f6e5b4f89170000000008ac6a006a536551652bebeaa2013e779c05000000000665ac5363635100000000", "ac", 0, 2028978692, "58294f0d7f2e68fe1fd30c01764fe1619bcc7961d68968944a0e263af6550437"], + ["c2b0b99001acfecf7da736de0ffaef8134a9676811602a6299ba5a2563a23bb09e8cbedf9300000000026300ffffffff042997c50300000000045252536a272437030000000007655353ab6363ac663752030000000002ab6a6d5c900000000000066a6a5265abab00000000", "52ac525163515251", 0, -894181723, "8b300032a1915a4ac05cea2f7d44c26f2a08d109a71602636f15866563eaafdc"], + ["82f9f10304c17a9d954cf3380db817814a8c738d2c811f0412284b2c791ec75515f38c4f8c020000000265ab5729ca7db1b79abee66c8a757221f29280d0681355cb522149525f36da760548dbd7080a0100000001510b477bd9ce9ad5bb81c0306273a3a7d051e053f04ecf3a1dbeda543e20601a5755c0cfae030000000451ac656affffffff71141a04134f6c292c2e0d415e6705dfd8dcee892b0d0807828d5aeb7d11f5ef0300000001520b6c6dc802a6f3dd0000000000056aab515163bfb6800300000000015300000000", "", 3, -635779440, "d55ed1e6c53510f2608716c12132a11fb5e662ec67421a513c074537eeccc34b"], + ["8edcf5a1014b604e53f0d12fe143cf4284f86dc79a634a9f17d7e9f8725f7beb95e8ffcd2403000000046aabac52ffffffff01c402b5040000000005ab6a63525100000000", "6351525251acabab6a", 0, 1520147762, "cdc6906760b2829a45c94deeaf63943331a771afae0339ccb9a91f6e8278b133"], + ["2074bad5011847f14df5ea7b4afd80cd56b02b99634893c6e3d5aaad41ca7c8ee8e5098df003000000026a6affffffff018ad59700000000000900ac656a526551635300000000", "65635265", 0, -1804671183, "663c999a52288c9999bff36c9da2f8b78d5c61b8347538f76c164ccba9868d0a"], + ["7100b11302e554d4ef249ee416e7510a485e43b2ba4b8812d8fe5529fe33ea75f36d392c4403000000020000ffffffff3d01a37e075e9a7715a657ae1bdf1e44b46e236ad16fd2f4c74eb9bf370368810000000007636553ac536365ffffffff01db696a0400000000065200ac656aac00000000", "63005151", 0, -1210499571, "b8b5d6aa8080eb1b04f9b3b86f718705ccc5f6537b15a5ab59c3394e9236207b"], + ["02c1017802091d1cb08fec512db7b012fe4220d57a5f15f9e7676358b012786e1209bcff950100000004acab6352ffffffff799bc282724a970a6fea1828984d0aeb0f16b67776fa213cbdc4838a2f1961a3010000000951516a536552ab6aabffffffff016c7b4b03000000000865abac5253ac5352b70195ad", "65655200516a", 0, -241626954, "be567cb47170b34ff81c66c1142cb9d27f9b6898a384d6dfc4fce16b75b6cb14"], + ["cb3178520136cd294568b83bb2520f78fecc507898f4a2db2674560d72fd69b9858f75b3b502000000066aac00515100ffffffff03ab005a01000000000563526363006e3836030000000001abfbda3200000000000665ab0065006500000000", "ab516a0063006a5300", 0, 1182109235, "0d1dbc32f241b9e7735a154d91b3f5cc566e644c2e53eadca4f00cb5880fa1df"], + ["18a4b0c004702cf0e39686ac98aab78ad788308f1d484b1ddfe70dc1997148ba0e28515c310300000000ffffffff05275a52a23c59da91129093364e275da5616c4070d8a05b96df5a2080ef259500000000096aac51656a6aac53ab66e64966b3b36a07dd2bb40242dd4a3743d3026e7e1e0d9e9e18f11d068464b989661321030000000265ac383339c4fae63379cafb63b0bab2eca70e1f5fc7d857eb5c88ccd6c0465093924bba8b2a000000000300636ab5e0545402bc2c4c010000000000cd41c002000000000000000000", "abac635253656a00", 3, 2052372230, "32db877b6b1ca556c9e859442329406f0f8246706522369839979a9f7a235a32"], + ["1d9c5df20139904c582285e1ea63dec934251c0f9cf5c47e86abfb2b394ebc57417a81f67c010000000353515222ba722504800d3402000000000353656a3c0b4a0200000000000fb8d20500000000076300ab005200516462f30400000000015200000000", "ab65", 0, -210854112, "edf73e2396694e58f6b619f68595b0c1cdcb56a9b3147845b6d6afdb5a80b736"], + ["4504cb1904c7a4acf375ddae431a74de72d5436efc73312cf8e9921f431267ea6852f9714a01000000066a656a656553a2fbd587c098b3a1c5bd1d6480f730a0d6d9b537966e20efc0e352d971576d0f87df0d6d01000000016321aeec3c4dcc819f1290edb463a737118f39ab5765800547522708c425306ebfca3f396603000000055300ac656a1d09281d05bfac57b5eb17eb3fa81ffcedfbcd3a917f1be0985c944d473d2c34d245eb350300000007656a51525152ac263078d9032f470f0500000000066aac00000052e12da60200000000003488410200000000076365006300ab539981e432", "52536a52526a", 1, -31909119, "f0a2deee7fd8a3a9fad6927e763ded11c940ee47e9e6d410f94fda5001f82e0c"], + ["14bc7c3e03322ec0f1311f4327e93059c996275302554473104f3f7b46ca179bfac9ef753503000000016affffffff9d405eaeffa1ca54d9a05441a296e5cc3a3e32bb8307afaf167f7b57190b07e00300000008abab51ab5263abab45533aa242c61bca90dd15d46079a0ab0841d85df67b29ba87f2393cd764a6997c372b55030000000452005263ffffffff0250f40e02000000000651516a0063630e95ab0000000000046a5151ac00000000", "6a65005151", 0, -1460947159, "fe9db879fe828b339df2679ff7f1b175a0f91485c81feae709f8942b9e7f02ba"], + ["2b3bd0dd04a1832f893bf49a776cd567ec4b43945934f4786b615d6cb850dfc0349b33301a000000000565ac000051cf80c670f6ddafab63411adb4d91a69c11d9ac588898cbfb4cb16061821cc104325c895103000000025163ffffffffa9e2d7506d2d7d53b882bd377bbcc941f7a0f23fd15d2edbef3cd9df8a4c39d10200000009ac63006a52526a5265ffffffff44c099cdf10b10ce87d4b38658d002fd6ea17ae4a970053c05401d86d6e75f99000000000963ab53526a5252ab63ffffffff035af69c01000000000100ba9b8b0400000000004cead10500000000026a520b77d667", "ab52abac526553", 3, -1955078229, "92d0938192f19ac04741905dbb61bb75e9872e577fe9a6bb2dcdfeb375140929"], + ["35df11f004a48ba439aba878fe9df20cc935b4a761c262b1b707e6f2b33e2bb7565cd68b130000000000ffffffffb2a2f99abf64163bb57ca900500b863f40c02632dfd9ea2590854c5fb4811da90200000006ac006363636affffffffaf9d89b2a8d2670ca37c8f7c140600b81259f2e037cb4590578ec6e37af8bf200000000005abac6a655270a4751eb551f058a93301ffeda2e252b6614a1fdd0e283e1d9fe53c96c5bbaafaac57b8030000000153ffffffff020d9f3b02000000000100ed7008030000000004abac000000000000", "abac", 3, 593793071, "88fdee1c2d4aeead71d62396e28dc4d00e5a23498eea66844b9f5d26d1f21042"], + ["a08ff466049fb7619e25502ec22fedfb229eaa1fe275aa0b5a23154b318441bf547989d0510000000005ab5363636affffffff2b0e335cb5383886751cdbd993dc0720817745a6b1c9b8ab3d15547fc9aafd03000000000965656a536a52656a532b53d10584c290d3ac1ab74ab0a19201a4a039cb59dc58719821c024f6bf2eb26322b33f010000000965ac6aac0053ab6353ffffffff048decba6ebbd2db81e416e39dde1f821ba69329725e702bcdea20c5cc0ecc6402000000086363ab5351ac6551466e377b0468c0fa00000000000651ab53ac6a513461c6010000000008636a636365535100eeb3dc010000000006526a52ac516a43f362010000000005000063536500000000", "0063516a", 1, -1158911348, "f6a1ecb50bd7c2594ebecea5a1aa23c905087553e40486dade793c2f127fdfae"], + ["5ac2f17d03bc902e2bac2469907ec7d01a62b5729340bc58c343b7145b66e6b97d434b30fa000000000163ffffffff44028aa674192caa0d0b4ebfeb969c284cb16b80c312d096efd80c6c6b094cca000000000763acabac516a52ffffffff10c809106e04b10f9b43085855521270fb48ab579266e7474657c6c625062d2d030000000351636595a0a97004a1b69603000000000465ab005352ad68010000000008636a5263acac5100da7105010000000002acab90325200000000000000000000", "6a6aab516a63526353", 2, 1518400956, "f7efb74b1dcc49d316b49c632301bc46f98d333c427e55338be60c7ef0d953be"], + ["aeb2e11902dc3770c218b97f0b1960d6ee70459ecb6a95eff3f05295dc1ef4a0884f10ba460300000005516352526393e9b1b3e6ae834102d699ddd3845a1e159aa7cf7635edb5c02003f7830fee3788b795f20100000009ab006a526553ac006ad8809c570469290e0400000000050000abab00b10fd5040000000008ab655263abac53ab630b180300000000009d9993040000000002516300000000", "5351ababac6a65", 0, 1084852870, "f2286001af0b0170cbdad92693d0a5ebaa8262a4a9d66e002f6d79a8c94026d1"], + ["9860ca9a0294ff4812534def8c3a3e3db35b817e1a2ddb7f0bf673f70eab71bb79e90a2f3100000000086a636551acac5165ffffffffed4d6d3cd9ff9b2d490e0c089739121161a1445844c3e204296816ab06e0a83702000000035100ac88d0db5201c3b59a050000000005ac6a0051ab00000000", "535263ab006a526aab", 1, -962088180, "e88fbe640dd9c462e4b70d29bf396aefd1d862abacb850286bc47a28de443898"], + ["4ddaa680026ec4d8060640304b86823f1ac760c260cef81d85bd847952863d629a3002b54b0200000008526365636a656aab65457861fc6c24bdc760c8b2e906b6656edaf9ed22b5f50e1fb29ec076ceadd9e8ebcb6b000000000152ffffffff033ff04f00000000000551526a00657a1d900300000000002153af040000000003006a6300000000", "ab526a53acabab", 0, 1055317633, "7f21b62267ed52462e371a917eb3542569a4049b9dfca2de3c75872b39510b26"], + ["01e76dcd02ad54cbc8c71d68eaf3fa7c883b65d74217b30ba81f1f5144ef80b706c0dc82ca000000000352ab6a078ec18bcd0514825feced2e8b8ea1ccb34429fae41c70cc0b73a2799e85603613c6870002000000086363ab6365536a53ffffffff043acea90000000000016ad20e1803000000000100fa00830200000000056352515351e864ee00000000000865535253ab6a6551d0c46672", "6a6365abacab", 0, -1420559067, "cd53bd33a6c66a2822c2c15cc453906c3a61635de489918ff78b10b20ddf0de1"], + ["fa00b26402670b97906203434aa967ce1559d9bd097d56dbe760469e6032e7ab61accb54160100000006635163630052fffffffffe0d3f4f0f808fd9cfb162e9f0c004601acf725cd7ea5683bbdc9a9a433ef15a0200000005ab52536563d09c7bef049040f305000000000153a7c7b9020000000004ac63ab52847a2503000000000553ab00655390ed80010000000005006553ab52860671d4", "536565ab52", 0, 799022348, "51eaaece5c1312569e6b4b73e3bd0a31617eed73f8cae79cc100c59b7b8e4887"], + ["cb5c06dc01b022ee6105ba410f0eb12b9ce5b5aa185b28532492d839a10cef33d06134b91b010000000153ffffffff02cec0530400000000005e1e4504000000000865656551acacac6a00000000", "ab53", 0, -1514251329, "136beb95459fe6b126cd6cefd54eb5d971524b0e883e41a292a78f78015cb8d5"], + ["f10a0356031cd569d652dbca8e7a4d36c8da33cdff428d003338602b7764fe2c96c505175b010000000465ac516affffffffbb54563c71136fa944ee20452d78dc87073ac2365ba07e638dce29a5d179da600000000003635152ffffffff9a411d8e2d421b1e6085540ee2809901e590940bbb41532fa38bd7a16b68cc350100000007535251635365636195df1603b61c45010000000002ab65bf6a310400000000026352fcbba10200000000016aa30b7ff0", "5351", 0, 1552495929, "9eb8adf2caecb4bf9ac59d7f46bd20e83258472db2f569ee91aba4cf5ee78e29"], + ["c3325c9b012f659466626ca8f3c61dfd36f34670abc054476b7516a1839ec43cd0870aa0c0000000000753525265005351e7e3f04b0112650500000000000363ac6300000000", "acac", 0, -68961497, "db4e8d4bc83fff79f12c07405e2835d992e338242e1fc8593160ab088aa5c552"], + ["2333e54c044370a8af16b9750ac949b151522ea6029bacc9a34261599549581c7b4e5ece470000000007510052006563abffffffff80630fc0155c750ce20d0ca4a3d0c8e8d83b014a5b40f0b0be0dd4c63ac28126020000000465000000ffffffff1b5f1433d38cdc494093bb1d62d84b10abbdae57e3d04e82e600857ab3b1dc990300000003515100b76564be13e4890a908ea7508afdad92ec1b200a9a67939fadce6eb7a29eb4550a0a28cb0300000001acffffffff02926c930300000000016373800201000000000153d27ee740", "ab6365ab516a53", 3, 598653733, "7047d88bcf9df6459d8d710b6f379c10b041e627723ebb6a5e9e27a2fad8d295"], + ["b500ca48011ec57c2e5252e5da6432089130603245ffbafb0e4c5ffe6090feb629207eeb0e010000000652ab6a636aab8302c9d2042b44f40500000000015278c05a050000000004ac5251524be080020000000007636aac63ac5252c93a9a04000000000965ab6553636aab5352d91f9ddb", "52005100", 0, -2024394741, "0a3909ebc8760eb66d315399fb96bdb3a8f11cade0dfcf478d1129463d1ad0ea"], + ["f52ff64b02ee91adb01f3936cc42e41e1672778962b68cf013293d649536b519bc3271dd2c00000000020065afee11313784849a7c15f44a61cd5fd51ccfcdae707e5896d131b082dc9322a19e12858501000000036aac654e8ca882022deb7c020000000006006a515352abd3defc0000000000016300000000", "63520063", 0, 1130989496, "7f208df9a5507e98c62cebc5c1e2445eb632e95527594929b9577b53363e96f6"], + ["ab7d6f36027a7adc36a5cf7528fe4fb5d94b2c96803a4b38a83a675d7806dda62b380df86a0000000003000000ffffffff5bc00131e29e22057c04be854794b4877dda42e416a7a24706b802ff9da521b20000000007ac6a0065ac52ac957cf45501b9f06501000000000500ac6363ab25f1110b", "00526500536a635253", 0, 911316637, "5fa09d43c8aef6f6fa01c383a69a5a61a609cd06e37dce35a39dc9eae3ddfe6c"], + ["f940888f023dce6360263c850372eb145b864228fdbbb4c1186174fa83aab890ff38f8c9a90300000000ffffffff01e80ccdb081e7bbae1c776531adcbfb77f2e5a7d0e5d0d0e2e6c8758470e85f00000000020053ffffffff03b49088050000000004656a52ab428bd604000000000951630065ab63ac636a0cbacf0400000000070063ac5265ac53d6e16604", "ac63", 0, 39900215, "713ddeeefcfe04929e7b6593c792a4efbae88d2b5280d1f0835d2214eddcbad6"], + ["530ecd0b01ec302d97ef6f1b5a6420b9a239714013e20d39aa3789d191ef623fc215aa8b940200000005ac5351ab6a3823ab8202572eaa04000000000752ab6a51526563fd8a270100000000036a006581a798f0", "525153656a0063", 0, 1784562620, "5e95a7910b3dafa4c56f614728e3a85395c21f8790ffcb61f747920363fd6141"], + ["5d781d9303acfcce964f50865ddfddab527ea971aee91234c88e184979985c00b4de15204b0100000003ab6352a009c8ab01f93c8ef2447386c434b4498538f061845862c3f9d5751ad0fce52af442b3a902000000045165ababb909c66b5a3e7c81b3c45396b944be13b8aacfc0204f3f3c105a66fa8fa6402f1b5efddb01000000096a65ac636aacab656ac3c677c402b79fa4050000000004006aab5133e35802000000000751ab635163ab0078c2e025", "6aac51636a6a005265", 0, -882306938, "fd19e57550358aa81f30761db32b7a697af52d201e9c516c7f05d2f7e95ea9d2"], + ["25ee54ef0187387564bb86e0af96baec54289ca8d15e81a507a2ed6668dc92683111dfb7a50100000004005263634cecf17d0429aa4d000000000007636a6aabab5263daa75601000000000251ab4df70a01000000000151980a890400000000065253ac6a006377fd24e3", "65ab", 0, 797877378, "069f38fd5d47abff46f04ee3ae27db03275e9aa4737fa0d2f5394779f9654845"], + ["a9c57b1a018551bcbc781b256642532bbc09967f1cbe30a227d352a19365d219d3f11649a3030000000451655352b140942203182894030000000006ab00ac6aab654add350400000000003d379505000000000553abacac00e1739d36", "5363", 0, -1069721025, "6da32416deb45a0d720a1dbe6d357886eabc44029dd5db74d50feaffbe763245"], + ["05c4fb94040f5119dc0b10aa9df054871ed23c98c890f1e931a98ffb0683dac45e98619fdc0200000007acab6a525263513e7495651c9794c4d60da835d303eb4ee6e871f8292f6ad0b32e85ef08c9dc7aa4e03c9c010000000500ab52acacfffffffffee953259cf14ced323fe8d567e4c57ba331021a1ef5ac2fa90f7789340d7c550100000007ac6aacac6a6a53ffffffff08d9dc820d00f18998af247319f9de5c0bbd52a475ea587f16101af3afab7c210100000003535363569bca7c0468e34f00000000000863536353ac51ac6584e319010000000006650052ab6a533debea030000000003ac0053ee7070020000000006ac52005253ac00000000", "6351005253", 2, 1386916157, "76c4013c40bfa1481badd9d342b6d4b8118de5ab497995fafbf73144469e5ff0"], + ["c95ab19104b63986d7303f4363ca8f5d2fa87c21e3c5d462b99f1ebcb7c402fc012f5034780000000009006aac63ac65655265ffffffffbe91afa68af40a8700fd579c86d4b706c24e47f7379dad6133de389f815ef7f501000000046aac00abffffffff1520db0d81be4c631878494668d258369f30b8f2b7a71e257764e9a27f24b48701000000076a515100535300b0a989e1164db9499845bac01d07a3a7d6d2c2a76e4c04abe68f808b6e2ef5068ce6540e0100000009ac53636a63ab65656affffffff0309aac6050000000005ab6563656a6067e8020000000003ac536aec91c8030000000009655251ab65ac6a53acc7a45bc5", "63526a65abac", 1, 512079270, "fb7eca81d816354b6aedec8cafc721d5b107336657acafd0d246049556f9e04b"], + ["ca66ae10049533c2b39f1449791bd6d3f039efe0a121ab7339d39ef05d6dcb200ec3fb2b3b020000000465006a53ffffffff534b8f97f15cc7fb4f4cea9bf798472dc93135cd5b809e4ca7fe4617a61895980100000000ddd83c1dc96f640929dd5e6f1151dab1aa669128591f153310d3993e562cc7725b6ae3d903000000046a52536582f8ccddb8086d8550f09128029e1782c3f2624419abdeaf74ecb24889cc45ac1a64492a0100000002516a4867b41502ee6ccf03000000000752acacab52ab6a4b7ba80000000000075151ab0052536300000000", "6553", 2, -62969321, "714105357240a2f6c0f03e0f4ec728b38a290e416a3dd149f48e51b999ebcd0a"], + ["ba646d0b0453999f0c70cb0430d4cab0e2120457bb9128ed002b6e9500e9c7f8d7baa20abe0200000001652a4e42935b21db02b56bf6f08ef4be5adb13c38bc6a0c3187ed7f6197607ba6a2c47bc8a03000000040052516affffffffa55c3cbfc19b1667594ac8681ba5d159514b623d08ed4697f56ce8fcd9ca5b0b00000000096a6a5263ac655263ab66728c2720fdeabdfdf8d9fb2bfe88b295d3b87590e26a1e456bad5991964165f888c03a0200000006630051ac00acffffffff0176fafe0100000000070063acac65515200000000", "63", 1, 2002322216, "e7058382f0d68446978bc845edda0e3ac9677932d478fdf36999790c316dcc32"], + ["2ddb8f84039f983b45f64a7a79b74ff939e3b598b38f436def7edd57282d0803c7ef34968d02000000026a537eb00c4187de96e6e397c05f11915270bcc383959877868ba93bac417d9f6ed9f627a7930300000004516551abffffffffacc12f1bb67be3ae9f1d43e55fda8b885340a0df1175392a8bbd9f959ad3605003000000025163ffffffff02ff0f4700000000000070bd99040000000003ac53abf8440b42", "", 2, -393923011, "0133f1a161363b71dfb3a90065c7128c56bd0028b558b610142df79e055ab5c7"], + ["b21fc15403b4bdaa994204444b59323a7b8714dd471bd7f975a4e4b7b48787e720cbd1f5f00000000000ffffffff311533001cb85c98c1d58de0a5fbf27684a69af850d52e22197b0dc941bc6ca9030000000765ab6363ab5351a8ae2c2c7141ece9a4ff75c43b7ea9d94ec79b7e28f63e015ac584d984a526a73fe1e04e0100000007526352536a5365ffffffff02a0a9ea030000000002ab52cfc4f300000000000465525253e8e0f342", "000000", 1, 1305253906, "0a8824608e2f3636a5c374d268d29579a12f89b85a8d56717a6d03832c6e68cf"], + ["d1704d6601acf710b19fa753e307cfcee2735eada0d982b5df768573df690f460281aad12d0000000007656300005100acffffffff0232205505000000000351ab632ca1bc0300000000016300000000", "ac65ab65ab51", 0, 165179664, "40b4f03c68288bdc996011b0f0ddb4b48dc3be6762db7388bdc826113266cd6c"], + ["d2f6c096025cc909952c2400bd83ac3d532bfa8a1f8f3e73c69b1fd7b8913379793f3ce92202000000076a00ab6a53516ade5332d81d58b22ed47b2a249ab3a2cb3a6ce9a6b5a6810e18e3e1283c1a1b3bd73e3ab00300000002acabffffffff01a9b2d40500000000056352abab00dc4b7f69", "ab0065", 0, -78019184, "2ef025e907f0fa454a2b48a4f3b81346ba2b252769b5c35d742d0c8985e0bf5e"], + ["3e6db1a1019444dba461247224ad5933c997256d15c5d37ade3d700506a0ba0a57824930d7010000000852ab6500ab00ac00ffffffff03389242020000000001aba8465a0200000000086a6a636a5100ab52394e6003000000000953ac51526351000053d21d9800", "abababacab53ab65", 0, 1643661850, "1f8a3aca573a609f4aea0c69522a82fcb4e15835449da24a05886ddc601f4f6a"], + ["f821a042036ad43634d29913b77c0fc87b4af593ac86e9a816a9d83fd18dfcfc84e1e1d57102000000076a63ac52006351ffffffffbcdaf490fc75086109e2f832c8985716b3a624a422cf9412fe6227c10585d21203000000095252abab5352ac526affffffff2efed01a4b73ad46c7f7bc7fa3bc480f8e32d741252f389eaca889a2e9d2007e000000000353ac53ffffffff032ac8b3020000000009636300000063516300d3d9f2040000000006510065ac656aafa5de0000000000066352ab5300ac9042b57d", "525365", 1, 667065611, "0d17a92c8d5041ba09b506ddf9fd48993be389d000aad54f9cc2a44fcc70426b"], + ["58e3f0f704a186ef55d3919061459910df5406a9121f375e7502f3be872a449c3f2bb058380100000000f0e858da3ac57b6c973f889ad879ffb2bd645e91b774006dfa366c74e2794aafc8bbc871010000000751ac65516a515131a68f120fd88ca08687ceb4800e1e3fbfea7533d34c84fef70cc5a96b648d580369526d000000000600ac00515363f6191d5b3e460fa541a30a6e83345dedfa3ed31ad8574d46d7bbecd3c9074e6ba5287c24020000000151e3e19d6604162602010000000004005100ac71e17101000000000065b5e90300000000040053ab53f6b7d101000000000200ac00000000", "6563ab", 1, -669018604, "8221d5dfb75fc301a80e919e158e0b1d1e86ffb08870a326c89408d9bc17346b"], + ["efec1cce044a676c1a3d973f810edb5a9706eb4cf888a240f2b5fb08636bd2db482327cf500000000005ab51656a52ffffffff46ef019d7c03d9456e5134eb0a7b5408d274bd8e33e83df44fab94101f7c5b650200000009ac5100006353630051407aadf6f5aaffbd318fdbbc9cae4bd883e67d524df06bb006ce2f7c7e2725744afb76960100000005536aab53acec0d64eae09e2fa1a7c4960354230d51146cf6dc45ee8a51f489e20508a785cbe6ca86fc000000000651536a516300ffffffff014ef598020000000006636aac655265a6ae1b75", "53516a5363526563ab", 2, -1823982074, "f0e0ca3e5ab96f89ff4cfb817b06bdb52467696bfc203f854372ecf2dfe240f7"], + ["3c436c2501442a5b700cbc0622ee5143b34b1b8021ea7bbc29e4154ab1f5bdfb3dff9d640501000000086aab5251ac5252acffffffff0170b9a20300000000066aab6351525114b13791", "63acabab52ab51ac65", 0, -2140612852, "25aaecec7c113a71003d3bc740cc5bffd5e5244a228d3fda96be2300488bcf9d"], + ["d62f183e037e0d52dcf73f9b31f70554bce4f693d36d17552d0e217041e01f15ad3840c838000000000963acac6a6a6a63ab63ffffffffabdfb395b6b4e63e02a763830f536fc09a35ff8a0cf604021c3c751fe4c88f4d0300000006ab63ab65ac53aa4d30de95a2327bccf9039fb1ad976f84e0b4a0936d82e67eafebc108993f1e57d8ae39000000000165ffffffff04364ad30500000000036a005179fd84010000000007ab636aac6363519b9023030000000008510065006563ac6acd2a4a02000000000000000000", "52", 1, 595020319, "20504bb3573277fd81e5da73e9d01a2daeb75d118e15ef019160c1ff94848413"], + ["44c200a5021238de8de7d80e7cce905606001524e21c8d8627e279335554ca886454d692e6000000000500acac52abbb8d1dc876abb1f514e96b21c6e83f429c66accd961860dc3aed5071e153e556e6cf076d02000000056553526a51870a928d0360a580040000000004516a535290e1e302000000000851ab6a00510065acdd7fc5040000000007515363ab65636abb1ec182", "6363", 0, -785766894, "ed53cc766cf7cb8071cec9752460763b504b2183442328c5a9761eb005c69501"], + ["d682d52d034e9b062544e5f8c60f860c18f029df8b47716cabb6c1b4a4b310a0705e754556020000000400656a0016eeb88eef6924fed207fba7ddd321ff3d84f09902ff958c815a2bf2bb692eb52032c4d803000000076365ac516a520099788831f8c8eb2552389839cfb81a9dc55ecd25367acad4e03cfbb06530f8cccf82802701000000085253655300656a53ffffffff02d543200500000000056a510052ac03978b05000000000700ac51525363acfdc4f784", "", 2, -696035199, "5bfc9023a113edc2c45c6b13708d584db89533a260f511b23fe6a65d344e66c1"], + ["e8c0dec5026575ddf31343c20aeeca8770afb33d4e562aa8ee52eeda6b88806fdfd4fe0a97030000000953acabab65ab516552ffffffffdde122c2c3e9708874286465f8105f43019e837746686f442666629088a970e0010000000153ffffffff01f98eee0100000000025251fe87379a", "63", 1, 633826334, "abe441209165d25bc6d8368f2e7e7dc21019056719fef1ace45542aa2ef282e2"], + ["b288c331011c17569293c1e6448e33a64205fc9dc6e35bc756a1ac8b97d18e912ea88dc0770200000007635300ac6aacabfc3c890903a3ccf8040000000004656500ac9c65c9040000000009ab6a6aabab65abac63ac5f7702000000000365005200000000", "526a63", 0, 1574937265, "96467a36a310014efd228dffe52930cf6f47cd7743d19b6009391f66799210c4"], + ["fc0a092003cb275fa9a25a72cf85d69c19e4590bfde36c2b91cd2c9c56385f51cc545530210000000004ab530063ffffffff729b006eb6d14d6e5e32b1c376acf1c62830a5d9246da38dbdb4db9f51fd1c74020000000463636500ffffffff0ae695c6d12ab7dcb8d3d4b547b03f178c7268765d1de9af8523d244e3836b12030000000151ffffffff0115c1e20100000000066a6aabac6a6a1ff59aec", "ab0053ac", 0, 931830962, "72c13aa4821a02ba3c9d3bf846db04d74db081c03ef0731b3b9c8a4b02dfc048"], + ["0fcae7e004a71a4a7c8f66e9450c0c1785268679f5f1a2ee0fb3e72413d70a9049ecff75de020000000452005251ffffffff99c8363c4b95e7ec13b8c017d7bb6e80f7c04b1187d6072961e1c2479b1dc0320200000000ffffffff7cf03b3d66ab53ed740a70c5c392b84f780fff5472aee82971ac3bfeeb09b2df0200000006ab5265636a0058e4fe9257d7c7c7e82ff187757c6eadc14cceb6664dba2de03a018095fd3006682a5b9600000000056353536a636de26b2303ff76de010000000001acdc0a2e020000000001ab0a53ed020000000007530063ab51510088417307", "ac6aacab5165535253", 2, -902160758, "a49424377407bc9ac9df02aa11203554257b5a1855574e3e93561efd7d27483f"], + ["612701500414271138e30a46b7a5d95c70c78cc45bf8e40491dac23a6a1b65a51af04e6b94020000000451655153ffffffffeb72dc0e49b2fad3075c19e1e6e4b387f1365dca43d510f6a02136318ddecb7f0200000003536352e115ffc4f9bae25ef5baf534a890d18106fb07055c4d7ec9553ba89ed1ac2101724e507303000000080063006563acabac2ff07f69a080cf61a9d19f868239e6a4817c0eeb6a4f33fe254045d8af2bca289a8695de0300000000430736c404d317840500000000086a00abac5351ab65306e0503000000000963ab0051536aabab6a6c8aca01000000000565516351ab5dcf960100000000016a00000000", "ab", 2, -604581495, "02debdc39f80da6901da02696b358105176bbc3818115320044c996e225b3ce6"], + ["6b68ba00023bb4f446365ea04d68d48539aae66f5b04e31e6b38b594d2723ab82d44512460000000000200acffffffff5dfc6febb484fff69c9eeb7c7eb972e91b6d949295571b8235b1da8955f3137b020000000851ac6352516a535325828c8a03365da801000000000800636aabac6551ab0f594d03000000000963ac536365ac63636a45329e010000000005abac53526a00000000", "005151", 0, 1317038910, "42f5ba6f5fe1e00e652a08c46715871dc4b40d89d9799fd7c0ea758f86eab6a7"], + ["aff5850c0168a67296cc790c1b04a9ed9ad1ba0469263a9432fcb53676d1bb4e0eea8ea1410100000005ac65526a537d5fcb1d01d9c26d0200000000065265ab5153acc0617ca1", "51ab650063", 0, 1712981774, "8449d5247071325e5f8edcc93cb9666c0fecabb130ce0e5bef050575488477eb"], + ["e6d6b9d8042c27aec99af8c12b6c1f7a80453e2252c02515e1f391da185df0874e133696b50300000006ac5165650065ffffffff6a4b60a5bfe7af72b198eaa3cde2e02aa5fa36bdf5f24ebce79f6ecb51f3b554000000000652656aababac2ec4c5a6cebf86866b1fcc4c5bd5f4b19785a8eea2cdfe58851febf87feacf6f355324a80100000001537100145149ac1e287cef62f6f5343579189fad849dd33f25c25bfca841cb696f10c5a34503000000046a636a63df9d7c4c018d96e20100000000015100000000", "53ab", 1, -1924777542, "f98f95d0c5ec3ac3e699d81f6c440d2e7843eab15393eb023bc5a62835d6dcea"], + ["046ac25e030a344116489cc48025659a363da60bc36b3a8784df137a93b9afeab91a04c1ed020000000951ab0000526a65ac51ffffffff6c094a03869fde55b9a8c4942a9906683f0a96e2d3e5a03c73614ea3223b2c29020000000500ab636a6affffffff3da7aa5ecef9071600866267674b54af1740c5aeb88a290c459caa257a2683cb0000000004ab6565ab7e2a1b900301b916030000000005abac63656308f4ed03000000000852ab53ac63ac51ac73d620020000000003ab00008deb1285", "6a", 2, 1299505044, "42a156112410052e7cec51a4b9f74116c7e88a1d01848243d75543542718b0cb"], + ["bd515acd0130b0ac47c2d87f8d65953ec7d657af8d96af584fc13323d0c182a2e5f9a96573000000000652ac51acac65ffffffff0467aade000000000003655363dc577d050000000006515252ab5300137f60030000000007535163530065004cdc860500000000036a5265241bf53e", "acab", 0, 621090621, "771d4d87f1591a13d77e51858c16d78f1956712fe09a46ff1abcabbc1e7af711"], + ["ff1ae37103397245ac0fa1c115b079fa20930757f5b6623db3579cb7663313c2dc4a3ffdb300000000076353656a000053ffffffff83c59e38e5ad91216ee1a312d15b4267bae2dd2e57d1a3fd5c2f0f809eeb5d46010000000800abab6a6a53ab51ffffffff9d5e706c032c1e0ca75915f8c6686f64ec995ebcd2539508b7dd8abc3e4d7d2a01000000006b2bdcda02a8fe070500000000045253000019e31d04000000000700ab63acab526a00000000", "53656aab6a525251", 0, 881938872, "726bb88cdf3af2f7603a31f33d2612562306d08972a4412a55dbbc0e3363721c"], + ["ff5400dd02fec5beb9a396e1cbedc82bedae09ed44bae60ba9bef2ff375a6858212478844b03000000025253ffffffff01e46c203577a79d1172db715e9cc6316b9cfc59b5e5e4d9199fef201c6f9f0f000000000900ab6552656a5165acffffffff02e8ce62040000000002515312ce3e00000000000251513f119316", "", 0, 1541581603, "2bdf3b36144803bb487fad5720810f3f6df618edc711f4ae144026b72c8b935d"], + ["28e3daa603c03626ad91ffd0ff927a126e28d29db5012588b829a06a652ea4a8a5732407030200000004ab6552acffffffff8e643146d3d0568fc2ad854fd7864d43f6f16b84e395db82b739f6f5c84d97b40000000004515165526b01c2dc1469db0198bd884e95d8f29056c48d7e74ff9fd37a9dec53e44b8769a6c99c030200000009ab006a516a53630065eea8738901002398000000000007ac5363516a51abeaef12f5", "52ab52515253ab", 2, 1687390399, "ba85293ce90eaf0561924272ff4ea752a2098968d0ccd5d01243a8fec3d1425a"], + ["b54bf5ac043b62e97817abb892892269231b9b220ba08bc8dbc570937cd1ea7cdc13d9676c010000000451ab5365a10adb7b35189e1e8c00b86250f769319668189b7993d6bdac012800f1749150415b2deb0200000003655300ffffffff60b9f4fb9a7e17069fd00416d421f804e2ef2f2c67de4ca04e0241b9f9c1cc5d0200000003ab6aacfffffffff048168461cce1d40601b42fbc5c4f904ace0d35654b7cc1937ccf53fe78505a0100000008526563525265abacffffffff01dbf4e6040000000007acac656553636500000000", "63", 2, 882302013, "245e080219f764d8155cb077bbdb8a959b39322fe41f74e1db785177bae5d08d"], + ["ebf628b30360bab3fa4f47ce9e0dcbe9ceaf6675350e638baff0c2c197b2419f8e4fb17e16000000000452516365ac4d909a79be207c6e5fb44fbe348acc42fc7fe7ef1d0baa0e4771a3c4a6efdd7e2c118b0100000003acacacffffffffa6166e9101f03975721a3067f1636cc390d72617be72e5c3c4f73057004ee0ee010000000863636a6a516a5252c1b1e82102d8d54500000000000153324c900400000000015308384913", "0063516a51", 1, -1658428367, "eb2d8dea38e9175d4d33df41f4087c6fea038a71572e3bad1ea166353bf22184"], + ["d6a8500303f1507b1221a91adb6462fb62d741b3052e5e7684ea7cd061a5fc0b0e93549fa50100000004acab65acfffffffffdec79bf7e139c428c7cfd4b35435ae94336367c7b5e1f8e9826fcb0ebaaaea30300000000ffffffffd115fdc00713d52c35ea92805414bd57d1e59d0e6d3b79a77ee18a3228278ada020000000453005151ffffffff040231510300000000085100ac6a6a000063c6041c0400000000080000536a6563acac138a0b04000000000263abd25fbe03000000000900656a00656aac510000000000", "ac526aac6a00", 1, -2007972591, "13d12a51598b34851e7066cd93ab8c5212d60c6ed2dae09d91672c10ccd7f87c"], + ["658cb1c1049564e728291a56fa79987a4ed3146775fce078bd2e875d1a5ca83baf6166a82302000000056a656351ab2170e7d0826cbdb45fda0457ca7689745fd70541e2137bb4f52e7b432dcfe2112807bd720300000007006a0052536351ffffffff8715ca2977696abf86d433d5c920ef26974f50e9f4a20c584fecbb68e530af5101000000009e49d864155bf1d3c757186d29f3388fd89c7f55cc4d9158b4cf74ca27a35a1dd93f945502000000096a535353ac656351510d29fa870230b809040000000006ab6a6a526a633b41da050000000004ab6a6a65ed63bf62", "52acabac", 2, -1774073281, "53ab197fa7e27b8a3f99ff48305e67081eb90e95d89d7e92d80cee25a03a6689"], + ["e92492cc01aec4e62df67ea3bc645e2e3f603645b3c5b353e4ae967b562d23d6e043badecd0100000003acab65ffffffff02c7e5ea040000000002ab52e1e584010000000005536365515195d16047", "6551", 0, -424930556, "93c34627f526d73f4bea044392d1a99776b4409f7d3d835f23b03c358f5a61c2"], + ["02e242db04be2d8ced9179957e98cee395d4767966f71448dd084426844cbc6d15f2182e85030000000200650c8ffce3db9de9c3f9cdb9104c7cb26647a7531ad1ebf7591c259a9c9985503be50f8de30000000007ac6a51636a6353ffffffffa2e33e7ff06fd6469987ddf8a626853dbf30c01719efb259ae768f051f803cd30300000000fffffffffd69d8aead941683ca0b1ee235d09eade960e0b1df3cd99f850afc0af1b73e070300000001ab60bb602a011659670100000000076363526300acac00000000", "6353ab515251", 3, 1451100552, "bbc9069b8615f3a52ac8a77359098dcc6c1ba88c8372d5d5fe080b99eb781e55"], + ["b28d5f5e015a7f24d5f9e7b04a83cd07277d452e898f78b50aae45393dfb87f94a26ef57720200000008ababac630053ac52ffffffff046475ed040000000008ab5100526363ac65c9834a04000000000251abae26b30100000000040000ac65ceefb900000000000000000000", "ac6551ac6a536553", 0, -1756558188, "5848d93491044d7f21884eef7a244fe7d38886f8ae60df49ce0dfb2a342cd51a"], + ["efb8b09801f647553b91922a5874f8e4bb2ed8ddb3536ed2d2ed0698fac5e0e3a298012391030000000952ac005263ac52006affffffff04cdfa0f050000000007ac53ab51abac65b68d1b02000000000553ab65ac00d057d50000000000016a9e1fda010000000007ac63ac536552ac00000000", "6aac", 0, 1947322909, "9edbf5c4949735dacad52d7ff4b0f5dbc8b8a7076f751da17f113d8d76740b12"], + ["68a59fb901c21946797e7d07a4a3ea86978ce43df0479860d7116ac514ba955460bae78fff0000000001abffffffff03979be80100000000036553639300bc040000000008006552006a656565cfa78d0000000000076552acab63ab5100000000", "ab65ab", 0, 995583673, "3b320dd47f2702452a49a1288bdc74a19a4b849b132b6cad9a1d945d87dfbb23"], + ["67761f2a014a16f3940dcb14a22ba5dc057fcffdcd2cf6150b01d516be00ef55ef7eb07a830100000004636a6a51ffffffff01af67bd050000000008526553526300510000000000", "6a00", 0, 1570943676, "079fa62e9d9d7654da8b74b065da3154f3e63c315f25751b4d896733a1d67807"], + ["e20fe96302496eb436eee98cd5a32e1c49f2a379ceb71ada8a48c5382df7c8cd88bdc47ced03000000016556aa0e180660925a841b457aed0aae47fca2a92fa1d7afeda647abf67198a3902a7c80dd00000000085152ac636a535265bd18335e01803c810100000000046500ac52f371025e", "6363ab", 1, -651254218, "2921a0e5e3ba83c57ba57c25569380c17986bf34c366ec216d4188d5ba8b0b47"], + ["4e1bd9fa011fe7aa14eee8e78f27c9fde5127f99f53d86bc67bdab23ca8901054ee8a8b6eb0300000009ac535153006a6a0063ffffffff044233670500000000000a667205000000000652ab636a51abe5bf35030000000003535351d579e505000000000700630065ab51ac3419ac30", "52abac52", 0, -1807563744, "93f23d51e7508c9554e4911e7e64fec217822e94dd6585d8300f900f3fee42d4"], + ["ec02fbee03120d02fde12574649660c441b40d330439183430c6feb404064d4f507e704f3c0100000000ffffffffe108d99c7a4e5f75cc35c05debb615d52fac6e3240a6964a29c1704d98017fb60200000002ab63fffffffff726ec890038977adfc9dadbeaf5e486d5fcb65dc23acff0dd90b61b8e2773410000000002ac65e9dace55010f881b010000000005ac00ab650000000000", "51ac525152ac6552", 2, -1564046020, "3f988922d8cd11c7adff1a83ce9499019e5ab5f424752d8d361cf1762e04269b"], + ["23dbdcc1039c99bf11938d8e3ccec53b60c6c1d10c8eb6c31197d62c6c4e2af17f52115c3a0300000008636352000063ababffffffff17823880e1df93e63ad98c29bfac12e36efd60254346cac9d3f8ada020afc0620300000003ab63631c26f002ac66e86cd22a25e3ed3cb39d982f47c5118f03253054842daadc88a6c41a2e1500000000096a00ab636a53635163195314de015570fd0100000000096a5263acab5200005300000000", "ababac6a6553", 1, 11586329, "bd36a50e0e0a4ecbf2709e68daef41eddc1c0c9769efaee57910e99c0a1d1343"], + ["33b03bf00222c7ca35c2f8870bbdef2a543b70677e413ce50494ac9b22ea673287b6aa55c50000000005ab00006a52ee4d97b527eb0b427e4514ea4a76c81e68c34900a23838d3e57d0edb5410e62eeb8c92b6000000000553ac6aacac42e59e170326245c000000000009656553536aab516aabb1a10603000000000852ab52ab6a516500cc89c802000000000763ac6a63ac516300000000", "", 0, 557416492, "38e9eb58ee0ee65fb8b9b21bc076c09341d7bbcd7323f84fd19e1decfaff404c"], + ["813eda1103ac8159850b4524ef65e4644e0fc30efe57a5db0c0365a30446d518d9b9aa8fdd0000000003656565c2f1e89448b374b8f12055557927d5b33339c52228f7108228149920e0b77ef0bcd69da60000000006abac00ab63ab82cdb7978d28630c5e1dc630f332c4245581f787936f0b1e84d38d33892141974c75b4750300000004ac53ab65ffffffff0137edfb02000000000000000000", "0063", 1, -1948560639, "f004d57d57a79070fb18090a0280706d5df4f25890cc640999fdd048fe74deb6"], + ["9e45d9aa0248c16dbd7f435e8c54ae1ad086de50c7b25795a704f3d8e45e1886386c653fbf01000000025352fb4a1acefdd27747b60d1fb79b96d14fb88770c75e0da941b7803a513e6d4c908c6445c7010000000163ffffffff014069a8010000000001520a794fb3", "51ac005363", 1, -719113284, "0d31a221c69bd322ef7193dd7359ddfefec9e0a1521d4a8740326d46e44a5d6a"], + ["36e42018044652286b19a90e5dd4f8d9f361d0760d080c5c5add1970296ff0f1de630233c8010000000200ac39260c7606017d2246ee14ddb7611586178067e6a4be38e788e33f39a3a95a55a13a6775010000000352ac638bea784f7c2354ed02ea0b93f0240cdfb91796fa77649beee6f7027caa70778b091deee700000000066a65ac656363ffffffff4d9d77ab676d711267ef65363f2d192e1bd55d3cd37f2280a34c72e8b4c559d700000000056a006aab00001764e1020d30220100000000085252516aacab0053472097040000000009635353ab6a636a5100a56407a1", "006a536551ab53ab", 0, 827296034, "daec2af5622bbe220c762da77bab14dc75e7d28aa1ade9b7f100798f7f0fd97a"], + ["5e06159a02762b5f3a5edcdfc91fd88c3bff08b202e69eb5ba74743e9f4291c4059ab008200000000001ac348f5446bb069ef977f89dbe925795d59fb5d98562679bafd61f5f5f3150c3559582992d0000000008ab5165515353abac762fc67703847ec6010000000000e200cf040000000002abaca64b86010000000008520000515363acabb82b491b", "ab53525352ab6a", 0, -61819505, "75a7db0df41485a28bf6a77a37ca15fa8eccc95b5d6014a731fd8adb9ada0f12"], + ["a1948872013b543d6d902ccdeead231c585195214ccf5d39f136023855958436a43266911501000000086aac006a6a6a51514951c9b2038a538a04000000000452526563c0f345050000000007526a5252ac526af9be8e03000000000752acac51ab006306198db2", "ab6353", 0, -326384076, "ced7ef84aad4097e1eb96310e0d1c8e512cfcb392a01d9010713459b23bc0cf4"], + ["c3efabba03cb656f154d1e159aa4a1a4bf9423a50454ebcef07bc3c42a35fb8ad84014864d0000000000d1cc73d260980775650caa272e9103dc6408bdacaddada6b9c67c88ceba6abaa9caa2f7d020000000553536a5265ffffffff9f946e8176d9b11ff854b76efcca0a4c236d29b69fb645ba29d406480427438e01000000066a0065005300ffffffff040419c0010000000003ab6a63cdb5b6010000000009006300ab5352656a63f9fe5e050000000004acac5352611b980100000000086a00acac00006a512d7f0c40", "0053", 0, -59089911, "c503001c16fbff82a99a18d88fe18720af63656fccd8511bca1c3d0d69bd7fc0"], + ["efb55c2e04b21a0c25e0e29f6586be9ef09f2008389e5257ebf2f5251051cdc6a79fce2dac020000000351006affffffffaba73e5b6e6c62048ba5676d18c33ccbcb59866470bb7911ccafb2238cfd493802000000026563ffffffffe62d7cb8658a6eca8a8babeb0f1f4fa535b62f5fc0ec70eb0111174e72bbec5e0300000009abababac516365526affffffffbf568789e681032d3e3be761642f25e46c20322fa80346c1146cb47ac999cf1b0300000000b3dbd55902528828010000000001ab0aac7b0100000000015300000000", "acac52", 3, 1638140471, "ad57ae7653e7701e36aa265191cc4289c7b54ab10e4d5c6eeea3439846870f67"], + ["91d3b21903629209b877b3e1aef09cd59aca6a5a0db9b83e6b3472aceec3bc2109e64ab85a0200000003530065ffffffffca5f92de2f1b7d8478b8261eaf32e5656b9eabbc58dcb2345912e9079a33c4cd010000000700ab65ab00536ad530611da41bbd51a389788c46678a265fe85737b8d317a83a8ff7a839debd18892ae5c80300000007ab6aac65ab51008b86c501038b8a9a05000000000263525b3f7a040000000007ab535353ab00abd4e3ff04000000000665ac51ab65630b7b656f", "6551525151516a00", 2, 499657863, "c27766033a1593fd751b8099515c58d30ca6ebdd4a3398bd9e740b0824cbb076"], + ["5d5c41ad0317aa7e40a513f5141ad5fc6e17d3916eebee4ddb400ddab596175b41a111ead20100000005536a5265acffffffff900ecb5e355c5c9f278c2c6ea15ac1558b041738e4bffe5ae06a9346d66d5b2b00000000080000ab636a65ab6affffffff99f4e08305fa5bd8e38fb9ca18b73f7a33c61ff7b3c68e696b30a04fea87f3ca000000000163d3d1760d019fc13a00000000000000000000", "ab53acabab6aac6a52", 2, 1007461922, "4012f5ff2f1238a0eb84854074670b4703238ebc15bfcdcd47ffa8498105fcd9"], + ["ceecfa6c02b7e3345445b82226b15b7a097563fa7d15f3b0c979232b138124b62c0be007890200000009abac51536a63525253ffffffffbae481ccb4f15d94db5ec0d8854c24c1cc8642bd0c6300ede98a91ca13a4539a0200000001ac50b0813d023110f5020000000006acabac526563e2b0d0040000000009656aac0063516a536300000000", "0063526500", 0, -1862053885, "3c703b314451d39023cfd425fda390f516607d41875ea3243954b8c5ed1744a5"], + ["ae62d5fd0380c4083a26642159f51af24bf55dc69008e6b7769442b6a69a603edd980a33000000000005ab5100ab53ffffffff49d048324d899d4b8ed5e739d604f5806a1104fede4cb9f92cc825a7fa7b4bfe0200000005536a000053ffffffff42e5cea5673c650881d0b4005fa4550fd86de5f21509c4564a379a0b7252ac0e0000000007530000526a53525f26a68a03bfacc3010000000000e2496f000000000009ab5253acac52636563b11cc600000000000700510065526a6a00000000", "abab", 1, -1600104920, "5ea481f7f6e66a1f72bea66573a3bcabf979a189c56f58ce9186d4015907efe3"], + ["f06f64af04fdcb830464b5efdb3d5ee25869b0744005375481d7b9d7136a0eb8828ad1f0240200000003516563fffffffffd3ba192dabe9c4eb634a1e3079fca4f072ee5ceb4b57deb6ade5527053a92c5000000000165ffffffff39f43401a36ba13a5c6dd7f1190e793933ae32ee3bf3e7bfb967be51e681af760300000009650000536552636a528e34f50b21183952cad945a83d4d56294b55258183e1627d6e8fb3beb8457ec36cadb0630000000005abab530052334a7128014bbfd10100000000085352ab006a63656afc424a7c", "53650051635253ac00", 2, 313254936, "e274dc213dca9687f36dfd7bc230340ab9f189acf6a3d16ec491695062d6527a"], + ["6dfd2f98046b08e7e2ef5fff153e00545faf7076699012993c7a30cb1a50ec528281a9022f030000000152ffffffff1f535e4851920b968e6c437d84d6ecf586984ebddb7d5db6ae035bd02ba222a8010000000651006a53ab51605072acb3e17939fa0737bc3ee43bc393b4acd58451fc4ffeeedc06df9fc649828822d5010000000253525a4955221715f27788d302382112cf60719be9ae159c51f394519bd5f7e70a4f9816c7020200000009526a6a51636aab656a36d3a5ff0445548e0100000000086a6a00516a52655167030b050000000004ac6a63525cfda8030000000000e158200000000000010000000000", "535263ac6a65515153", 3, 585774102, "9ecee0edf57dedac5f66c4c2ea86af02dc34cf99a32423311b641293827469f4"], + ["187eafed01389a45e75e9dda526d3acbbd41e6414936b3356473d1f9793d161603efdb45670100000002ab00ffffffff04371c8202000000000563630063523b3bde02000000000753516563006300e9e765010000000005516aac656a373f9805000000000665525352acab08d46763", "ab", 0, 122457992, "393aa6c758e0eed15fa4af6d9e2d7c63f49057246dbb92b4268ec24fc87301ca"], + ["7d50b977035d50411d814d296da9f7965ddc56f3250961ca5ba805cadd0454e7c521e31b0300000000003d0416c2cf115a397bacf615339f0e54f6c35ffec95aa009284d38390bdde1595cc7aa7c0100000005ab52ac5365ffffffff4232c6e796544d5ac848c9dc8d25cfa74e32e847a5fc74c74d8f38ca51188562030000000653ac51006a51ffffffff016bd8bb00000000000465ab5253163526f3", "51ab526a00005353", 1, -1311316849, "29ba2848a81550d3b6f18c85f122946fabc09ff5508dc90a8b0fe6190d142dcb"], + ["2a45cd1001bf642a2315d4a427eddcc1e2b0209b1c6abd2db81a800c5f1af32812de42032702000000050051525200ffffffff032177db050000000005530051abac49186f000000000004ab6aab00645c0000000000000765655263acabac00000000", "6a65", 0, -1774715722, "6a9ac3f7da4c7735fbc91f728b52ecbd602233208f96ac5592656074a5db118a"], + ["479358c202427f3c8d19e2ea3def6d6d3ef2281b4a93cd76214f0c7d8f040aa042fe19f71f0300000001abffffffffa2709be556cf6ecaa5ef530df9e4d056d0ed57ce96de55a5b1f369fa40d4e74a020000000700006a51635365c426be3f02af578505000000000363ab63fd8f590500000000065153abac53632dfb14b3", "520063ab51", 1, -763226842, "9d9eed80d7c63ba4ff2aea728c380e8442e4777e6fb104a036fc7d37911cea74"], + ["76179a8e03bec40747ad65ab0f8a21bc0d125b5c3c17ad5565556d5cb03ade7c83b4f32d98030000000151ffffffff99b900504e0c02b97a65e24f3ad8435dfa54e3c368f4e654803b756d011d24150200000003ac5353617a04ac61bb6cf697cfa4726657ba35ed0031432da8c0ffb252a190278830f9bd54f0320100000006656551005153c8e8fc8803677c77020000000007ac6553535253ac70f442030000000001535be0f20200000000026300bf46cb3a", "6aab52", 1, -58495737, "e067a76918548d48eed6cf12cb6f0bb5e2390cd09b2f589acbbc5b31a2ba48b2"], + ["75ae53c2042f7546223ce5d5f9e00a968ddc68d52e8932ef2013fa40ce4e8c6ed0b6195cde01000000056563ac630079da0452c20697382e3dba6f4fc300da5f52e95a9dca379bb792907db872ba751b8024ee0300000009655151536500005163ffffffffe091b6d43f51ff00eff0ccfbc99b72d3aff208e0f44b44dfa5e1c7322cfc0c5f01000000075200005363ab63ffffffff7e96c3b83443260ac5cfd18258574fbc4225c630d3950df812bf51dceaeb0f9103000000065365655165639a6bf70b01b3e14305000000000563530063ac00000000", "6300ab00ac", 2, 982422189, "ee4ea49d2aae0dbba05f0b9785172da54408eb1ec67d36759ff7ed25bfc28766"], + ["1cdfa01e01e1b8078e9c2b0ca5082249bd18fdb8b629ead659adedf9a0dd5a04031871ba120200000008525351536565ab6affffffff011e28430200000000076a5363636aac52b2febd4a", "abacac63656300", 0, 387396286, "0be6c7750fffc0b3999a0a89d5abaa8dda2a6a9df794699960844a2c7b3c03bd"], + ["cc28c1810113dfa6f0fcd9c7d9c9a30fb6f1d774356abeb527a8651f24f4e6b25cf763c4e00300000003ab636affffffff02dfc6050000000000080053636351ab0052afd56903000000000453ab5265f6c90d99", "006551abacacac", 0, 1299280774, "f5ff8e9e8c119958788e0a1e37e6b4e9f8a6927e1504230a5c6680eed7e451e0"], + ["ca816e7802cd43d66b9374cd9bf99a8da09402d69c688d8dcc5283ace8f147e1672b757e020200000005516aabab5240fb06c95c922342279fcd88ba6cd915933e320d7becac03192e0941e0345b79223e89570300000004005151ac353ecb5d0264dfbd010000000005ac6aacababd5d70001000000000752ac53ac6a5151ec257f71", "63ac", 1, 774695685, "cc180c4f797c16a639962e7aec58ec4b209853d842010e4d090895b22e7a7863"], + ["b42b955303942fedd7dc77bbd9040aa0de858afa100f399d63c7f167b7986d6c2377f66a7403000000066aac00525100ffffffff0577d04b64880425a3174055f94191031ad6b4ca6f34f6da9be7c3411d8b51fc000000000300526a6391e1cf0f22e45ef1c44298523b516b3e1249df153590f592fcb5c5fc432dc66f3b57cb03000000046a6aac65ffffffff0393a6c9000000000004516a65aca674ac0400000000046a525352c82c370000000000030053538e577f89", "", 1, -1237095008, "f90da2feebfd6791134d6087fcac2d35ccdd88f0fe6adbec6260f40b0c2f1e1d"], + ["92c9fe210201e781b72554a0ed5e22507fb02434ddbaa69aff6e74ea8bad656071f1923f3f02000000056a63ac6a514470cef985ba83dcb8eee2044807bedbf0d983ae21286421506ae276142359c8c6a34d68020000000863ac63525265006aa796dd0102ca3f9d05000000000800abab52ab535353cd5c83010000000007ac00525252005322ac75ee", "5165", 0, 97879971, "6e6307cef4f3a9b386f751a6f40acebab12a0e7e17171d2989293cbec7fd45c2"], + ["ccca1d5b01e40fe2c6b3ee24c660252134601dab785b8f55bd6201ffaf2fddc7b3e2192325030000000365535100496d4703b4b66603000000000665535253ac633013240000000000015212d2a502000000000951abac636353636a5337b82426", "0052", 0, -1691630172, "577bf2b3520b40aef44899a20d37833f1cded6b167e4d648fc5abe203e43b649"], + ["bc1a7a3c01691e2d0c4266136f12e391422f93655c71831d90935fbda7e840e50770c61da20000000008635253abac516353ffffffff031f32aa020000000003636563786dbc0200000000003e950f00000000000563516a655184b8a1de", "51536a", 0, -1627072969, "10af74e0145d7a20c4ad8ca5ef9cf2f31e43c9fc435f1b4f52e58adc9b21709c"], + ["076d209e02d904a6c40713c7225d23e7c25d4133c3c3477828f98c7d6dbd68744023dbb66b030000000753ab00536565acffffffff10975f1b8db8861ca94c8cc7c7cff086ddcd83e10b5fffd4fc8f2bdb03f9463c0100000000ffffffff029dff76010000000006526365530051a3be6004000000000000000000", "515253ac65acacac", 1, -1207502445, "66c488603b2bc53f0d22994a1f0f66fb2958203102eba30fe1d37b27a55de7a5"], + ["690fd1f80476db1f9eebe91317f2f130a60cbc1f4feadd9d6474d438e9cb7f91e4994600af0300000004ab536a63a15ce9fa6622d0c4171d895b42bff884dc6e8a7452f827fdc68a29c3c88e6fdee364eaf50000000002ab52ffffffff022dc39d3c0956b24d7f410b1e387859e7a72955f45d6ffb1e884d77888d18fe0300000005ac6a63656afffffffff10b06bce1800f5c49153d24748fdefb0bf514c12863247d1042d56018c3e25c03000000086a63ac6365536a52ffffffff031f162f0500000000060000655265abffbcd40500000000045151ac001a9c8c05000000000652ac53656a6300000000", "ac51ab63acac", 0, -67986012, "051c0df7ac688c2c930808dabde1f50300aea115f2bb3334f4753d5169b51e46"], + ["49ac2af00216c0307a29e83aa5de19770e6b20845de329290bd69cf0e0db7aed61ae41b39002000000035163ac8b2558ef84635bfc59635150e90b61fc753d34acfd10d97531043053e229cd720133cd95000000000463516a51ffffffff02458471040000000008abab636a51ac0065545aa80000000000096a6553516a5263ac6a00000000", "51526300ab5363", 1, 1449668540, "ddfd902bba312a06197810da96a0ddccb595f96670b28ded7dba88d8cd0469b8"], + ["fa4d868b024b010bd5dce46576c2fb489aa60bb797dac3c72a4836f49812c5c564c258414f03000000007a9b3a585e05027bdd89edbadf3c85ac61f8c3a04c773fa746517ae600ff1a9d6b6c02fb0200000004515163abffffffff01b17d020500000000046a65520000000000", "536565ab65635363", 0, -1718953436, "fb28283f22775136148f3848fc52cc4245b3efa60330d93f61164ff7ff8a65b5"], + ["cac6382d0462375e83b67c7a86c922b569a7473bfced67f17afd96c3cd2d896cf113febf9e0300000003006a53ffffffffaa4913b7eae6821487dd3ca43a514e94dcbbf350f8cc4cafff9c1a88720711b800000000096a6a525300acac6353ffffffff184fc4109c34ea27014cc2c1536ef7ed1821951797a7141ddacdd6e429fae6ff01000000055251655200ffffffff9e7b79b4e6836e290d7b489ead931cba65d1030ccc06f20bd4ca46a40195b33c030000000008f6bc8304a09a2704000000000563655353511dbc73050000000000cf34c500000000000091f76e0000000000085200ab00005100abd07208cb", "0063656a", 2, -1488731095, "3d21547cd848397bdfec047f58e08e8564f4bf4b7e7c80d19d2f7da3660efed2"], + ["1711146502c1a0b82eaa7893976fefe0fb758c3f0e560447cef6e1bde11e42de91a125f71c030000000015bd8c04703b4030496c7461482481f290c623be3e76ad23d57a955807c9e851aaaa20270300000000d04abaf20326dcb7030000000001632225350400000000075263ac00520063dddad9020000000000af23d148", "52520053510063", 0, 1852122766, "22da4b95c7acb5cf04934d5fd6237301faa2a78dd18bbab24a2c91223778c675"], + ["8d5b124d0231fbfc640c706ddb1d57bb49a18ba8ca0e1101e32c7e6e65a0d4c7971d93ea360100000008acabac0000abac65ffffffff8fe0fd7696597b845c079c3e7b87d4a44110c445a330d70342a5501955e17dd70100000004ab525363ef22e8a90346629f030000000009516a00ac63acac51657bd57b05000000000200acfd4288050000000009acab5352ab00ab636300000000", "53ac526553ab65", 0, 1253152911, "cab9b1e6957b002478d9500b3740fd74a3efd001fa08e26ccffd004a43fc626f"], + ["38146dc502c7430e92b6708e9e107b61cd38e5e773d9395e5c8ad8986e7e4c03ee1c1e1e760100000000c8962ce2ac1bb3b1285c0b9ba07f4d2e5ce87c738c42ac0548cd8cec1100e6928cd6b0b6010000000763ab636aab52527cccefbd04e5f6f8020000000006006aabacac65ab2c4a00000000000351635209a6f40100000000026aacce57dc040000000008ab5353ab516a516a00000000", "ab", 0, -1205978316, "3d5fec59077cc693240232741158adbb62cb642efc56ffc6efac8e9eb58622db"], + ["22d81c740469695a6a83a9a4824f77ecff8804d020df23713990afce2b72591ed7de98500502000000065352526a6a6affffffff90dc85e118379b1005d7bbc7d2b8b0bab104dad7eaa49ff5bead892f17d8c3ba010000000665656300ab51ffffffff965193879e1d5628b52005d8560a35a2ba57a7f19201a4045b7cbab85133311d0200000003ac005348af21a13f9b4e0ad90ed20bf84e4740c8a9d7129632590349afc03799414b76fd6e826200000000025353ffffffff04a0d40d04000000000060702700000000000652655151516ad31f1502000000000365ac0069a1ac0500000000095100655300ab53525100000000", "51636a52ac", 0, -1644680829, "bf6bbbf2709bf3416f136b5539bc0e10aa9176a13abc73bf655a958fc3047ff1"], + ["a27dcbc801e3475174a183586082e0914c314bc9d79d1570f29b54591e5e0dff07fbb45a7f0000000004ac53ab51ffffffff027347f5020000000005535351ab63d0e5c9030000000009ac65ab6a63515200ab7cd632ed", "ac63636553", 0, -686435306, "883a6ea3b2cc53fe8a803c229106366ca14d25ffbab9fef8367340f65b201da6"], + ["b123ed2204410d4e8aaaa8cdb95234ca86dad9ff77fb4ae0fd4c06ebed36794f0215ede0040100000002ac63ffffffff3b58b81b19b90d8f402701389b238c3a84ff9ba9aeea298bbf15b41a6766d27a01000000056a6553ab00151824d401786153b819831fb15926ff1944ea7b03d884935a8bde01ed069d5fd80220310200000000ffffffffa9c9d246f1eb8b7b382a9032b55567e9a93f86c77f4e32c092aa1738f7f756c30100000002ab65ffffffff011a2b48000000000000ed44d1fb", "630051ab63", 2, -1118263883, "b5dab912bcabedff5f63f6dd395fc2cf030d83eb4dd28214baba68a45b4bfff0"], + ["1339051503e196f730955c5a39acd6ed28dec89b4dadc3f7c79b203b344511270e5747fa9900000000045151636affffffff378c6090e08a3895cedf1d25453bbe955a274657172491fd2887ed5c9aceca7b0100000000ffffffffcf7cc3c36ddf9d4749edfa9cefed496d2f86e870deb814bfcd3b5637a5496461030000000451006300ffffffff04dcf3fa010000000008526a63005263acabb41d84040000000004abac5153800eff020000000005656a535365106c5e00000000000000000000", "abac5300", 2, 2013719864, "841508014812cc91ea8fedf12db2daea675dde3f84adff9863223b108d411964"], + ["0728c606014c1fd6005ccf878196ba71a54e86cc8c53d6db500c3cc0ac369a26fac6fcbc210000000005ab53ac5365ba9668290182d7870100000000066a000053655100000000", "65", 0, 1789961524, "3684a5373d16131a38a69c1bf2eebb53a533f728bf0d65da71b4d9c389bc7796"], + ["a1134397034bf4067b6c81c581e2b73fb63835a08819ba24e4e92df73074bf773c94577df7000000000465525251ffffffff8b6608feaa3c1f35f49c6330a769716fa01c5c6f6e0cdc2eb10dfc99bbc21e77010000000952656aac005352655180a0bda4bc72002c2ea8262e26e03391536ec36867258cab968a6fd6ec7523b64fa1d8c001000000056a53ac6353ffffffff04dbeeed05000000000553650052abcd5d0e01000000000463abab51104b2e0500000000066aac53ac5165283ca7010000000004535252ab00000000", "ab515151516552ab", 1, -324598740, "68d42c87eeb35958c876b5ca25990646a2949d58ffd02a9ba2dce2512af56e3e"], + ["bcdafbae04aa18eb75855aeb1f5124f30044741351b33794254a80070940cb10552fa4fa8e0300000001acd0423fe6e3f3f88ae606f2e8cfab7a5ef87caa2a8f0401765ff9a47d718afcfb40c0099b0000000008ac6565ab53ac6aac645308009d680202d600e492b31ee0ab77c7c5883ebad5065f1ce87e4dfe6453e54023a0010000000151ffffffffb9d818b14245899e1d440152827c95268a676f14c3389fc47f5a11a7b38b1bde03000000026300ffffffff03cda22102000000000751ac535263005100a4d20400000000045200536ac8bef405000000000700ab51ab6563ac00000000", "6553516a526aab", 1, -2111409753, "5e1849e7368cf4f042718586d9bd831d61479b775bab97aba9f450042bd9876a"], + ["ed3bb93802ddbd08cb030ef60a2247f715a0226de390c9c1a81d52e83f8674879065b5f87d0300000003ab6552ffffffff04d2c5e60a21fb6da8de20bf206db43b720e2a24ce26779bca25584c3f765d1e0200000008ab656a6aacab00ab6e946ded025a811d04000000000951abac6352ac00ab5143cfa3030000000005635200636a00000000", "5352ac650065535300", 1, -668727133, "e9995065e1fddef72a796eef5274de62012249660dc9d233a4f24e02a2979c87"], + ["59f4629d030fa5d115c33e8d55a79ea3cba8c209821f979ed0e285299a9c72a73c5bba00150200000002636affffffffd8aca2176df3f7a96d0dc4ee3d24e6cecde1582323eec2ebef9a11f8162f17ac0000000007ab6565acab6553ffffffffeebc10af4f99c7a21cbc1d1074bd9f0ee032482a71800f44f26ee67491208e0403000000065352ac656351ffffffff0434e955040000000004ab515152caf2b305000000000365ac007b1473030000000003ab530033da970500000000060051536a5253bb08ab51", "", 2, 396340880, "79ea1cddf30ecd0abaf01ac2ac49fe2021f7924bddb8fc5c27c7c191b588560d"], + ["286e3eb7043902bae5173ac3b39b44c5950bc363f474386a50b98c7bdab26f98dc83449c4a020000000752ac6a00510051ffffffff4339cd6a07f5a5a2cb5815e5845da70300f5c7833788363bf7fe67595d3225520100000000fffffffff9c2dd8b06ad910365ffdee1a966f124378a2b8021065c8764f6138bb1e951380200000005ab5153ac6affffffff0370202aba7a68df85436ea7c945139513384ef391fa33d16020420b8ad40e9a000000000900ab5165526353abacffffffff020c1907000000000004abac526a1b490b040000000000df1528f7", "5353ab", 3, -1407529581, "21148b85eae8b5ffcde66861e5a4ea9951927ffb8aca853f1490844b615c6b39"], + ["2e245cf80179e2e95cd1b34995c2aff49fe4519cd7cee93ad7587f7f7e8105fc2dff206cd30200000009006a63516a6553ab52350435a201d5ed2d02000000000352ab6558552c89", "00ab53", 0, -233917810, "4605ae5fd3d50f9c45d37db7118a81a9ef6eb475d2333f59df5d3e216f150d49"], + ["33a98004029d262f951881b20a8d746c8c707ea802cd2c8b02a33b7e907c58699f97e42be80100000007ac53536552abacdee04cc01d205fd8a3687fdf265b064d42ab38046d76c736aad8865ca210824b7c622ecf02000000070065006a536a6affffffff01431c5d010000000000270d48ee", "", 1, 921554052, "a6fd14e4db99c3c573657156ce3336b211a9d76ed7d78a1f5cbdc475cd731b2b"], + ["aac18f2b02b144ed481557c53f2146ae523f24fcde40f3445ab0193b6b276c315dc2894d2300000000075165650000636a233526947dbffc76aec7db1e1baa6868ad4799c76e14794dcbaaec9e713a83967f6a65170200000005abac6551ab27d518be01b652a30000000000015300000000", "52ac5353", 1, 1559377072, "5b4e8507bcef72724e3e2f6037397c1da8fbf9dd5e65e25f8588008b279d313b"], + ["5ab79881033555b65fe58c928883f70ce7057426fbdd5c67d7260da0fe8b1b9e6a2674cb850300000009ac516aac6aac006a6affffffffa5be9223b43c2b1a4d120b5c5b6ec0484f637952a3252181d0f8e813e76e11580200000000e4b5ceb8118cb77215bbeedc9a076a4d087bb9cd1473ea32368b71daeeeacc451ec209010000000005acac5153aced7dc34e02bc5d11030000000005ac5363006a54185803000000000552ab00636a00000000", "5100", 1, 1927062711, "e9f53d531c12cce1c50abed4ac521a372b4449b6a12f9327c80020df6bff66c0"], + ["6c2c8fac0124b0b7d4b610c3c5b91dee32b7c927ac71abdf2d008990ca1ac40de0dfd530660300000006ababac5253656bd7eada01d847ec000000000004ac52006af4232ec8", "6a6a6a0051", 0, -340809707, "fb51eb9d7e47d32ff2086205214f90c7c139e08c257a64829ae4d2b301071c6a"], + ["6e3880af031735a0059c0bb5180574a7dcc88e522c8b56746d130f8d45a52184045f96793e0100000008acabac6a526a6553fffffffffe05f14cdef7d12a9169ec0fd37524b5fcd3295f73f48ca35a36e671da4a2f560000000008006a526a6351ab63ffffffffdfbd869ac9e472640a84caf28bdd82e8c6797f42d03b99817a705a24fde2736600000000010090a090a503db956b04000000000952ac53ab6a536a63ab358390010000000009656a5200525153ac65353ee204000000000763530052526aaba6ad83fb", "535151ab6300", 2, 222013954, "44830b0e5bcfe2f144ae8d3404d82f1e1d0b9a1644af65666d33797ea3d7480c"], + ["8df1cd19027db4240718dcaf70cdee33b26ea3dece49ae6917331a028c85c5a1fb7ee3e475020000000865ab6a00510063636157988bc84d8d55a8ba93cdea001b9bf9d0fa65b5db42be6084b5b1e1556f3602f65d4d0100000005ac00ab0052206c852902b2fb54030000000008ac5252536aacac5378c4a5050000000007acabac535163532784439e", "acab6a", 0, 1105620132, "edb7c74223d1f10f9b3b9c1db8064bc487321ff7bb346f287c6bc2fad83682de"], + ["0e803682024f79337b25c98f276d412bc27e56a300aa422c42994004790cee213008ff1b8303000000080051ac65ac655165f421a331892b19a44c9f88413d057fea03c3c4a6c7de4911fe6fe79cf2e9b3b10184b1910200000005525163630096cb1c670398277204000000000253acf7d5d502000000000963536a6a636a5363ab381092020000000002ac6a911ccf32", "6565", 1, -1492094073, "49678e45a7f1f54cb611176aeddb58cce9e0474455ef8433365cc842cb3974b8"], + ["7d71669d03022f9dd90edac323cde9e56354c6804c6b8e687e9ae699f46805aafb8bcaa636000000000253abffffffff698a5fdd3d7f2b8b000c68333e4dd58fa8045b3e2f689b889beeb3156cecdb490300000009525353abab0051acabc53f0aa821cdd69b473ec6e6cf45cf9b38996e1c8f52c27878a01ec8bb02e8cb31ad24e500000000055353ab0052ffffffff0447a23401000000000565ab53ab5133aaa0030000000006515163656563057d110300000000056a6aacac52cf13b5000000000003526a5100000000", "6a6a51", 1, -1349253571, "0ed8dcb42b9a0fa1de47b6ac2679e66d25a1564a1571679c6ac593201d6ef0fd"], + ["9ff618e60136f8e6bb7eabaaac7d6e2535f5fba95854be6d2726f986eaa9537cb283c701ff02000000026a65ffffffff012d1c0905000000000865ab00ac6a516a652f9ad240", "51515253635351ac", 0, 1571304323, "520d461a5840358c7aa826b63dfb4b6e2bfb14df5342cc3e8b1b5351d9fbf13f"], + ["9fbd43ac025e1462ecd10b1a9182a8e0c542f6d1089322a41822ab94361e214ed7e1dfdd8a020000000263519d0437581538e8e0b6aea765beff5b4f3a4a202fca6e5d19b34c141078c6688f71ba5b8e0100000003ac6552ffffffff02077774050000000009655153655263acab6a0ae4e10100000000035152524c97136b", "635152ab", 0, 1969622955, "d82d4ccd9b67810f26a378ad9592eb7a30935cbbd27e859b00981aefd0a72e08"], + ["0117c92004314b84ed228fc11e2999e657f953b6de3b233331b5f0d0cf40d5cc149b93c7b30300000005515263516a083e8af1bd540e54bf5b309d36ba80ed361d77bbf4a1805c7aa73667ad9df4f97e2da410020000000600ab6351ab524d04f2179455e794b2fcb3d214670001c885f0802e4b5e015ed13a917514a7618f5f332203000000086a536aab51000063ecf029e65a4a009a5d67796c9f1eb358b0d4bd2620c8ad7330fb98f5a802ab92d0038b1002000000036a6551a184a88804b04490000000000009ab6a5152535165526a33d1ab020000000001518e92320000000000002913df04000000000952abac6353525353ac8b19bfdf", "000051ab0000", 0, 489432995, "a12c6a73c8b68f35d3f03231cc43c58f4d763fa270f0d89a4123560f8509cb94"], + ["e7f5482903f98f0299e0984b361efb2fddcd9979869102281e705d3001a9d283fe9f3f3a1e02000000025365ffffffffcc5c7fe82feebad32a22715fc30bc584efc9cd9cadd57e5bc4b6a265547e676e0000000001ab579d21235bc2281e08bf5e7f8f64d3afb552839b9aa5c77cf762ba2366fffd7ebb74e49400000000055263ab63633df82cf40100982e05000000000453ac535300000000", "acacab", 2, -1362931278, "443361aa2c235e238c4bdae7343e6979305a60c33850be4a6baef16793422fa5"], + ["09adb2e90175ca0e816326ae2dce7750c1b27941b16f6278023dbc294632ab97977852a09d030000000465ab006affffffff027739cf0100000000075151ab63ac65ab8a5bb601000000000653ac5151520011313cdc", "ac", 0, -76831820, "b692dd6ceed3b2411e38e68637c3e10601d702074d905b166b896a3f37674016"], + ["f973867602e30f857855cd0364b5bbb894c049f44abbfd661d7ae5dbfeaafca89fac8959c20100000005ab52536a51ffffffffbeceb68a4715f99ba50e131884d8d20f4a179313691150adf0ebf29d05f8770303000000066352ab00ac63ffffffff021fddb90000000000036a656322a177000000000008526500ac5100acac84839083", "52acab53ac", 0, 1407879325, "db0329439490efc64b7104d6d009b03fbc6fac597cf54fd786fbbb5fd73b92b4"], + ["fd22ebaa03bd588ad16795bea7d4aa7f7d48df163d75ea3afebe7017ce2f350f6a0c1cb0bb00000000086aabac5153526363ffffffff488e0bb22e26a565d77ba07178d17d8f85702630ee665ec35d152fa05af3bda10200000004515163abffffffffeb21035849e85ad84b2805e1069a91bb36c425dc9c212d9bae50a95b6bfde1200300000001ab5df262fd02b69848040000000008ab6363636a6363ace23bf2010000000007655263635253534348c1da", "006353526563516a00", 0, -1491036260, "bd24809a43f0eeba1dc9adafe51f9b880c5a04e798b4185a2cd3bd5f0436dad5"], + ["130b462d01dd49fac019dc4442d0fb54eaa6b1c2d1ad0197590b7df26969a67abd7f3fbb4f0100000008ac65abac53ab6563ffffffff0345f825000000000004ac53acac9d5816020000000002ababeff8e90500000000086aab006552ac6a53a892dc55", "ab0065ac530052", 0, 944483348, "ee68d974f9f14b10dea7291709c34e61accda517a553738f2d0d688d070c7ef2"], + ["f8e50c2604609be2a95f6d0f31553081f4e1a49a0a30777fe51eb1c596c1a9a92c053cf28c0300000009656a51ac5252630052fffffffff792ed0132ae2bd2f11d4a2aab9d0c4fbdf9a66d9ae2dc4108afccdc14d2b1700100000007ab6a6563ac636a7bfb2fa116122b539dd6a2ab089f88f3bc5923e5050c8262c112ff9ce0a3cd51c6e3e84f02000000066551ac5352650d5e687ddf4cc9a497087cabecf74d236aa4fc3081c3f67b6d323cba795e10e7a171b725000000000852635351ab635100ffffffff02df5409020000000008ac6a53acab5151004156990200000000045163655200000000", "ac53abac65005300", 0, -173065064, "e1221e5d6e727d830bb332d84c8667ff4813ae651d661982115bc2b66a023656"], + ["18020dd1017f149eec65b2ec23300d8df0a7dd64fc8558b36907723c03cd1ba672bbb0f51d0300000005ab65ab6a63ffffffff037cd7ae000000000009ab516a65005352ac65f1e4360400000000056353530053f118f0040000000009536363ab006500abac00000000", "63ab51acab52ac", 0, -550412404, "e19b796c14a0373674968e342f2741d8b51092a5f8409e9bff7dcd52e56fcbcb"], + ["b04154610363fdade55ceb6942d5e5a723323863b48a0cb04fdcf56210717955763f56b08d0300000009ac526a525151635151ffffffff93a176e76151a9eabdd7af00ef2af72f9e7af5ecb0aa4d45d00618f394cdd03c030000000074d818b332ebe05dc24c44d776cf9d275c61f471cc01efce12fd5a16464157f1842c65cb00000000066a0000ac6352d3c4134f01d8a1c0030000000005520000005200000000", "5200656a656351", 2, -9758021, "670068081a458cf6f718e34aa21de66b62345fa8e3f49a0a27aa6a783ecaeada"], + ["9794b3ce033df7b1e32db62d2f0906b589eacdacf5743963dc2255b6b9a6cba211fadd0d41020000000600ab00650065ffffffffaae00687a6a4131152bbcaafedfaed461c86754b0bde39e2bef720e6d1860a0302000000070065516aac6552ffffffff50e4ef784d6230df7486e972e8918d919f005025bc2d9aacba130f58bed7056703000000075265ab52656a52ffffffff02c6f1a9000000000006005251006363cf450c040000000008abab63510053abac00000000", "ac0063ababab515353", 1, 2063905082, "fad092fc98f17c2c20e10ba9a8eb44cc2bcc964b006f4da45cb9ceb249c69698"], + ["94533db7015e70e8df715066efa69dbb9c3a42ff733367c18c22ff070392f988f3b93920820000000006535363636300ce4dac3e03169af80300000000080065ac6a53ac65ac39c050020000000006abacab6aacac708a02050000000005ac5251520000000000", "6553", 0, -360458571, "339cee0653af41d62e71ff919c714f241fa56fa73cf26fdd51b82e3856801145"], + ["c8597ada04f59836f06c224a2640b79f3a8a7b41ef3efa2602592ddda38e7597da6c639fee0300000009005251635351acabacffffffff4c518f347ee694884b9d4072c9e916b1a1f0a7fc74a1c90c63fdf8e5a185b6ae02000000007113af55afb41af7518ea6146786c7c726641c68c8829a52925e8d4afd07d8945f68e7230300000008ab00ab65ab650063ffffffffc28e46d7598312c420e11dfaae12add68b4d85adb182ae5b28f8340185394b63000000000165ffffffff04dbabb7010000000000ee2f6000000000000852ab6500ab6a51acb62a27000000000009ac53515300ac006a6345fb7505000000000752516a0051636a00000000", "", 3, 15199787, "0d66003aff5bf78cf492ecbc8fd40c92891acd58d0a271be9062e035897f317e"], + ["1a28c4f702c8efaad96d879b38ec65c5283b5c084b819ad7db1c086e85e32446c7818dc7a90300000008656351536a525165fa78cef86c982f1aac9c5eb8b707aee8366f74574c8f42ef240599c955ef4401cf578be30200000002ab518893292204c430eb0100000000016503138a0300000000040053abac60e0eb010000000005525200ab63567c2d030000000004abab52006cf81e85", "ab51525152", 1, 2118315905, "4e4c9a781f626b59b1d3ad8f2c488eb6dee8bb19b9bc138bf0dc33e7799210d4"], + ["c6c7a87003f772bcae9f3a0ac5e499000b68703e1804b9ddc3e73099663564d53ddc4e1c6e01000000076a536a6aac63636e3102122f4c30056ef8711a6bf11f641ddfa6984c25ac38c3b3e286e74e839198a80a34010000000165867195cd425821dfa2f279cb1390029834c06f018b1e6af73823c867bf3a0524d1d6923b0300000005acab53ab65ffffffff02fa4c49010000000008ab656a0052650053e001100400000000008836d972", "ac526351acab", 1, 978122815, "a869c18a0edf563d6e5eddd5d5ae8686f41d07f394f95c9feb8b7e52761531ca"], + ["0ea580ac04c9495ab6af3b8d59108bb4194fcb9af90b3511c83f7bb046d87aedbf8423218e02000000085152acac006363ab9063d7dc25704e0caa5edde1c6f2dd137ded379ff597e055b2977b9c559b07a7134fcef2000000000200aca89e50181f86e9854ae3b453f239e2847cf67300fff802707c8e3867ae421df69274449402000000056365abababffffffff47a4760c881a4d7e51c69b69977707bd2fb3bcdc300f0efc61f5840e1ac72cee0000000000ffffffff0460179a020000000004ab53ab52a5250c0500000000096565acac6365ab52ab6c281e02000000000952635100ac006563654e55070400000000046552526500000000", "ab526563acac53ab", 2, 1426964103, "a29c81dc9c7cb208942cae8ec043f90c12b0f9d1ab4054a4c98edd560a116a99"], + ["c33028b301d5093e1e8397270d75a0b009b2a6509a01861061ab022ca122a6ba935b8513320200000000ffffffff013bcf5a0500000000015200000000", "", 0, -513413204, "6b1459536f51482f5dbf42d7e561896557461e1e3b6bf67871e2b51faae2832c"], + ["43b2727901a7dd06dd2abf690a1ccedc0b0739cb551200796669d9a25f24f71d8d101379f50300000000ffffffff0418e031040000000000863d770000000000085352ac526563ac5174929e040000000004ac65ac00ec31ac0100000000066a51ababab5300000000", "65", 0, -492874353, "baad9d177012600624b88fe5c878f4fd66a40d4c02ff8c38d9c1bc1efa04283d"], + ["4763ed4401c3e6ab204bed280528e84d5288f9cac5fb8a2e7bd699c7b98d4df4ac0c40e55303000000066a6aacab5165ffffffff015b57f80400000000046a63535100000000", "ac51abab53", 0, -592611811, "ba38dbe4ca21ca7787df31cd7f92e1845cabf9c5e09fd840c095eae749b7c3f4"], + ["d24f647b02f71708a880e6819a1dc929c1a50b16447e158f8ff62f9ccd644e0ca3c592593702000000050053536a00ffffffff67868cd5414b6ca792030b18d649de5450a456407242b296d936bcf3db79e07b02000000005af6319c016022f50100000000036a516300000000", "6aab526353516a6a", 0, 1350782237, "fc388ed113d09f09a046708f756320d4f213cc5563fb50cbccd2f2a6ccbbe50a"], + ["fe6ddf3a02657e42a7496ef170b4a8caf245b925b91c7840fd28e4a22c03cb459cb498b8d603000000065263656a650071ce6bf8d905106f9f1faf6488164f3decac65bf3c5afe1dcee20e6bc3cb6d052561985a030000000163295b117601343dbb0000000000026563dba521df", "", 1, -1696179931, "d9684685c99ce48f398fb467a91a1a59629a850c429046fb3071f1fa9a5fe816"], + ["c61523ef0129bb3952533cbf22ed797fa2088f307837dd0be1849f20decf709cf98c6f032f03000000026563c0f1d378044338310400000000066363516a5165a14fcb0400000000095163536a6a00ab53657271d60200000000001d953f0500000000010000000000", "53516353005153", 0, 1141615643, "861f2b47443f635f3a62a4293ed2e26a59e5d248d8004a2e37d06ca5c06448e6"], + ["ba3dac6c0182562b0a26d475fe1e36315f0913b6869bdad0ecf21f1339a5fcbccd32056c840200000000ffffffff04300351050000000000220ed405000000000851abac636565ac53dbbd19020000000007636363ac6a52acbb005a0500000000016abd0c78a8", "63006a635151005352", 0, 1359658764, "a2feac551e4ae321377b99cfc3a9505dc6a9dc2b29d57ddcf43c5f7f41851afb"], + ["ac27e7f5025fc877d1d99f7fc18dd4cadbafa50e34e1676748cc89c202f93abf36ed46362101000000036300abffffffff958cd5381962b765e14d87fc9524d751e4752dd66471f973ed38b9d562e525620100000003006500ffffffff02b67120050000000004ac51516adc330c0300000000015200000000", "656352", 1, 15049991, "f3374253d64ac264055bdbcc32e27426416bd595b7c7915936c70f839e504010"], + ["edb30140029182b80c8c3255b888f7c7f061c4174d1db45879dca98c9aab8c8fed647a6ffc03000000086a53510052ab6300ffffffff82f65f261db62d517362c886c429c8fbbea250bcaad93356be6f86ba573e9d930100000000ffffffff04daaf150400000000016a86d1300100000000096a6353535252ac5165d4ddaf000000000002abab5f1c6201000000000000000000", "ab6a6a00ac", 0, -2058017880, "7e30b58503af00ed0bd97a1ecb84630922e96258104d668b23914264f32e2907"], + ["7e50207303146d1f7ad62843ae8017737a698498d4b9118c7a89bb02e8370307fa4fada41d000000000753006300005152b7afefc85674b1104ba33ef2bf37c6ed26316badbc0b4aa6cb8b00722da4f82ff3555a6c020000000900ac656363ac51ac52ffffffff93fab89973bd322c5d7ad7e2b929315453e5f7ada3072a36d8e33ca8bebee6e0020000000300acab930da52b04384b04000000000004650052ac435e380200000000076a6a515263ab6aa9494705000000000600ab6a525252af8ba90100000000096565acab526353536a279b17ad", "acac005263536aac63", 1, -34754133, "4e6357da0057fb7ff79da2cc0f20c5df27ff8b2f8af4c1709e6530459f7972b0"], + ["c05764f40244fb4ebe4c54f2c5298c7c798aa90e62c29709acca0b4c2c6ec08430b26167440100000008acab6a6565005253ffffffffc02c2418f398318e7f34a3cf669d034eef2111ea95b9f0978b01493293293a870100000000e563e2e00238ee8d040000000002acab03fb060200000000076500ac656a516aa37f5534", "52ab6a0065", 1, -2033176648, "83deef4a698b62a79d4877dd9afebc3011a5275dbe06e89567e9ef84e8a4ee19"], + ["5a59e0b9040654a3596d6dab8146462363cd6549898c26e2476b1f6ae42915f73fd9aedfda00000000036363abffffffff9ac9e9ca90be0187be2214251ff08ba118e6bf5e2fd1ba55229d24e50a510d53010000000165ffffffff41d42d799ac4104644969937522873c0834cc2fcdab7cdbecd84d213c0e96fd60000000000ffffffffd838db2c1a4f30e2eaa7876ef778470f8729fcf258ad228b388df2488709f8410300000000fdf2ace002ceb6d903000000000265654c1310040000000003ac00657e91c0ec", "536a63ac", 0, 82144555, "98ccde2dc14d14f5d8b1eeea5364bd18fc84560fec2fcea8de4d88b49c00695e"], + ["156ebc8202065d0b114984ee98c097600c75c859bfee13af75dc93f57c313a877efb09f230010000000463536a51ffffffff81114e8a697be3ead948b43b5005770dd87ffb1d5ccd4089fa6c8b33d3029e9c03000000066a5251656351ffffffff01a87f140000000000050000ac51ac00000000", "00", 0, -362221156, "0fb3318fdba7b9792195c332c9ef52173bc214b3457b9d1aa35c79ebcf9c0750"], + ["15e37793023c7cbf46e073428908fce0331e49550f2a42b92468827852693f0532a01c29f70200000007005353636351acffffffff38426d9cec036f00eb56ec1dcd193647e56a7577278417b8a86a78ac53199bc403000000056353006a53ffffffff04a25ce103000000000900ab5365656a526a63c8eff7030000000004526353537ab6db0200000000016a11a3fa02000000000651acacab526500000000", "53ac6aab6a6551", 0, 1117532727, "81516df6983addbc6383cefeed3f184bdbec473c0d3ae3e4cf22c160f6ea119b"], + ["f7a09f10027250fc1b70398fb5c6bffd2be9718d3da727e841a73596fdd63810c9e4520a6a010000000963ac516a636a65acac1d2e2c57ab28d311edc4f858c1663972eebc3bbc93ed774801227fda65020a7ec1965f780200000005ac5252516a8299fddc01dcbf7200000000000463ac6551960fda03", "65acab51", 1, 2017321737, "9c5fa02abfd34d0f9dec32bf3edb1089fca70016debdb41f4f54affcb13a2a2a"], + ["6d97a9a5029220e04f4ccc342d8394c751282c328bf1c132167fc05551d4ca4da4795f6d4e02000000076a0052ab525165ffffffff9516a205e555fa2a16b73e6db6c223a9e759a7e09c9a149a8f376c0a7233fa1b0100000007acab51ab63ac6affffffff04868aed04000000000652ac65ac536a396edf01000000000044386c0000000000076aab5363655200894d48010000000001ab8ebefc23", "6351526aac51", 1, 1943666485, "f0bd4ca8e97203b9b4e86bc24bdc8a1a726db5e99b91000a14519dc83fc55c29"], + ["8e3fddfb028d9e566dfdda251cd874cd3ce72e9dde837f95343e90bd2a93fe21c5daeb5eed01000000045151525140517dc818181f1e7564b8b1013fd68a2f9a56bd89469686367a0e72c06be435cf99db750000000003635251ffffffff01c051780300000000096552ababac6a65acab099766eb", "5163ab6a52ababab51", 1, 1296295812, "5509eba029cc11d7dd2808b8c9eb47a19022b8d8b7778893459bbc19ab7ea820"], + ["a603f37b02a35e5f25aae73d0adc0b4b479e68a734cf722723fd4e0267a26644c36faefdab0200000000ffffffff43374ad26838bf733f8302585b0f9c22e5b8179888030de9bdda180160d770650200000001004c7309ce01379099040000000005526552536500000000", "abababab005153", 0, 1409936559, "4ca73da4fcd5f1b10da07998706ffe16408aa5dff7cec40b52081a6514e3827e"], + ["9eeedaa8034471a3a0e3165620d1743237986f060c4434f095c226114dcb4b4ec78274729f03000000086a5365510052ac6afb505af3736e347e3f299a58b1b968fce0d78f7457f4eab69240cbc40872fd61b5bf8b120200000002ac52df8247cf979b95a4c97ecb8edf26b3833f967020cd2fb25146a70e60f82c9ee4b14e88b103000000008459e2fa0125cbcd05000000000000000000", "52ab5352006353516a", 0, -1832576746, "add9d72c079750fae3f116786bb66c850f5192481e537b23e1f1b00167b8f31d"], + ["05921d7c048cf26f76c1219d0237c226454c2a713c18bf152acc83c8b0647a94b13477c07f0300000003ac526afffffffff2f494453afa0cabffd1ba0a626c56f90681087a5c1bd81d6adeb89184b27b7402000000036a6352ffffffff0ad10e2d3ce355481d1b215030820da411d3f571c3f15e8daf22fe15342fed04000000000095f29f7b93ff814a9836f54dc6852ec414e9c4e16a506636715f569151559100ccfec1d100000000055263656a53ffffffff04f4ffef010000000008ac6a6aabacabab6a0e6689040000000006ab536a5352abe364d005000000000965536363655251ab53807e00010000000004526aab63f18003e3", "6363ac51", 3, -375891163, "030d2095b1f8b38c5d622299dd96aa289a6d165925162a921588bec8a12c5de0"], + ["b9b44d9f04b9f15e787d7704e6797d51bc46382190c36d8845ec68dfd63ee64cf7a467b21e00000000096aac00530052ab636aba1bcb110a80c5cbe073f12c739e3b20836aa217a4507648d133a8eedd3f02cb55c132b203000000076a000063526352b1c288e3a9ff1f2da603f230b32ef7c0d402bdcf652545e2322ac01d725d75f5024048ad0100000000ffffffffffd882d963be559569c94febc0ef241801d09dc69527c9490210f098ed8203c700000000056a006300ab9109298d01719d9a0300000000066a52ab006365d7894c5b", "ac6351650063636a", 3, -622355413, "1a0941119cb73a2114cad9f888df01095714cc51c178bf5d2603d4a5b1c7b4ca"], + ["ff60473b02574f46d3e49814c484081d1adb9b15367ba8487291fc6714fd6e3383d5b335f001000000026a6ae0b82da3dc77e5030db23d77b58c3c20fa0b70aa7d341a0f95f3f72912165d751afd57230300000008ac536563516a6363ffffffff04f86c0200000000000553acab636ab13111000000000003510065f0d3f305000000000951ab516a65516aabab730a3a010000000002515200000000", "ac6a", 1, 1895032250, "137bf02bde1d8b8387a0257d166c6a74ccfd7f49d5e18824cc40b904cebc4f63"], + ["f218026204f4f4fc3d3bd0eada07c57b88570d544a0436ae9f8b753792c0c239810bb30fbc0200000002536affffffff8a468928d6ec4cc10aa0f73047697970e99fa64ae8a3b4dca7551deb0b639149010000000851ab520052650051ffffffffa98dc5df357289c9f6873d0f5afcb5b030d629e8f23aa082cf06ec9a95f3b0cf0000000000ffffffffea2c2850c5107705fd380d6f29b03f533482fd036db88739122aac9eff04e0aa010000000365536a03bd37db034ac4c4020000000007515152655200ac33b27705000000000151efb71e0000000000007b65425b", "515151", 3, -1772252107, "8cb83000a14bfe12841613e43134537c287e6985e72a221f889b7b282fcf289e"], + ["48e7d42103b260b27577b70530d1ac2fed2551e9dd607cbcf66dca34bb8c03862cf8f5fd5401000000075151526aacab00ffffffff1e3d3b841552f7c6a83ee379d9d66636836673ce0b0eda95af8f2d2523c91813030000000665acac006365ffffffff388b3c386cd8c9ef67c83f3eaddc79f1ff910342602c9152ffe8003bce51b28b0100000008636363006a636a52ffffffff04b8f67703000000000852005353ac6552520cef720200000000085151ab6352ab00ab5096d6030000000005516a005100662582020000000001ac6c137280", "6a65", 1, 1513618365, "94c8cea5505d3846ca85ca65c2d9d63708ba235931ced4232600914e1662bb76"], + ["91ebc4cf01bc1e068d958d72ee6e954b196f1d85b3faf75a521b88a78021c543a06e056279000000000265ab7c12df0503832121030000000000cc41a6010000000005ab5263516540a951050000000006ab63ab65acac00000000", "526a0065636a6a6aac", 0, -614046542, "c4d85f57db54f2771cd2c2b2e5c6c1a7b982304f80486bc9dce61d8faf286c40"], + ["3cd4474201be7a6c25403bf00ca62e2aa8f8f4f700154e1bb4d18c66f7bb7f9b975649f0dc0100000006535151535153ffffffff01febbeb000000000006005151006aac00000000", "", 0, -1674687195, "c8a9608cbdc8a26ebd468f1ad1f31b4c324556c38696223f1b988a40ac7aa283"], + ["92fc95f00307a6b3e2572e228011b9c9ed41e58ddbaefe3b139343dbfb3b34182e9fcdc3f50200000002acab847bf1935fde8bcfe41c7dd99683289292770e7f163ad09deff0e0665ed473cd2b56b0f40300000006516551ab6351294dab312dd87b9327ce2e95eb44b712cfae0e50fda15b07816c8282e8365b643390eaab01000000026aacffffffff016e0b6b040000000001ac00000000", "650065acac005300", 2, -1885164012, "bd7d26bb3a98fc8c90c972500618bf894cb1b4fe37bf5481ff60eef439d3b970"], + ["4db591ab018adcef5f4f3f2060e41f7829ce3a07ea41d681e8cb70a0e37685561e4767ac3b0000000005000052acabd280e63601ae6ef20000000000036a636326c908f7", "ac6a51526300630052", 0, 862877446, "355ccaf30697c9c5b966e619a554d3323d7494c3ea280a9b0dfb73f953f5c1cb"], + ["503fd5ef029e1beb7b242d10032ac2768f9a1aca0b0faffe51cec24770664ec707ef7ede4f01000000045253ac53375e350cc77741b8e96eb1ce2d3ca91858c052e5f5830a0193200ae2a45b413dda31541f0000000003516553ffffffff0175a5ba0500000000015200000000", "6aab65510053ab65", 1, 1603081141, "90999ac56b85515eceea70b1080e86a715290ca4e99c4e473c1392dce9eff140"], + ["c80abebd042cfec3f5c1958ee6970d2b4586e0abec8305e1d99eb9ee69ecc6c2cbd76374380000000007ac53006300ac510acee933b44817db79320df8094af039fd82111c7726da3b33269d3820123694d849ee5001000000056a65ab526562699bea8530dc916f5d61f0babea709dac578774e8a4dcd9c640ec3aceb6cb2443f24f302000000020063ea780e9e57d1e4245c1e5df19b4582f1bf704049c5654f426d783069bcc039f2d8fa659f030000000851ab53635200006a8d00de0b03654e8500000000000463ab635178ebbb0400000000055100636aab239f1d030000000006ab006300536500000000", "6565ac515100", 3, 1460851377, "b35bb1b72d02fab866ed6bbbea9726ab32d968d33a776686df3ac16aa445871e"], + ["0337b2d5043eb6949a76d6632b8bb393efc7fe26130d7409ef248576708e2d7f9d0ced9d3102000000075352636a5163007034384dfa200f52160690fea6ce6c82a475c0ef1caf5c9e5a39f8f9ddc1c8297a5aa0eb02000000026a51ffffffff38e536298799631550f793357795d432fb2d4231f4effa183c4e2f61a816bcf0030000000463ac5300706f1cd3454344e521fde05b59b96e875c8295294da5d81d6cc7efcfe8128f150aa54d6503000000008f4a98c704c1561600000000000072cfa6000000000000e43def01000000000100cf31cc0500000000066365526a6500cbaa8e2e", "", 3, 2029506437, "7615b4a7b3be865633a31e346bc3db0bcc410502c8358a65b8127089d81b01f8"], + ["59f6cffd034733f4616a20fe19ea6aaf6abddb30b408a3a6bd86cd343ab6fe90dc58300cc90200000000ffffffffc835430a04c3882066abe7deeb0fa1fdaef035d3233460c67d9eabdb05e95e5a02000000080065ac535353ab00ffffffff4b9a043e89ad1b4a129c8777b0e8d87a014a0ab6a3d03e131c27337bbdcb43b402000000066a5100abac6ad9e9bf62014bb118010000000001526cbe484f", "ab526352ab65", 0, 2103515652, "4f2ccf981598639bec57f885b4c3d8ea8db445ea6e61cfd45789c69374862e5e"], + ["cbc79b10020b15d605680a24ee11d8098ad94ae5203cb6b0589e432832e20c27b72a926af20300000006ab65516a53acbb854f3146e55c508ece25fa3d99dbfde641a58ed88c051a8a51f3dacdffb1afb827814b02000000026352c43e6ef30302410a020000000000ff4bd90100000000065100ab63000008aa8e0400000000095265526565ac5365abc52c8a77", "53526aac0051", 0, 202662276, "dcd3c1f2da711cb846e0e568f24aef2332e88589eb48e16fc55d0475a325c6c4"], + ["7c07419202fa756d29288c57b5c2b83f3c847a807f4a9a651a3f6cd6c46034ae0aa3a7446b0200000004ab6a6365ffffffff9da83cf4219bb96c76f2d77d5df31c1411a421171d9b59ec02e5c1218f29935403000000008c13879002f8b1ac0400000000086a63536a636553653c584f02000000000000000000", "abac53ab656363", 1, -1038419525, "4a74f365a161bc6c9bddd249cbd70f5dadbe3de70ef4bd745dcb6ee1cd299fbd"], + ["351cbb57021346e076d2a2889d491e9bfa28c54388c91b46ee8695874ad9aa576f1241874d0200000008ab6563525300516affffffffe13e61b8880b8cd52be4a59e00f9723a4722ea58013ec579f5b3693b9e115b1100000000096363abac5252635351ffffffff027fee02040000000008ab6a5200ab006a65b85f130200000000086a52630053ab52ab00000000", "ab6aab65", 1, 586415762, "b6b31beffacd9e26b8a5d1caa8a7bca03112d0d96a06aeca66b1731e10982ff9"], + ["a8252ea903f1e8ff953adb16c1d1455a5036222c6ea98207fc21818f0ece2e1fac310f9a0100000000095163ac635363ac0000be6619e9fffcde50a0413078821283ce3340b3993ad00b59950bae7a9f931a9b0a3a035f010000000463005300b8b0583fbd6049a1715e7adacf770162811989f2be20af33f5f60f26eba653dc26b024a00000000006525351636552ffffffff046d2acc030000000002636a9a2d430500000000080065005165ab53abecf63204000000000052b9ed050000000008acacac53ab65656500000000", "65ab53635253636a51", 2, 1442638995, "d64186e356877b60c0a6506f5490bb29363415a3343fddfcd2f7dc2264f35ce9"], + ["2f1a425c0471a5239068c4f38f9df135b1d24bf52d730d4461144b97ea637504495aec360801000000055300515365c71801dd1f49f376dd134a9f523e0b4ae611a4bb122d8b26de66d95203f181d09037974300000000025152ffffffff9bdcea7bc72b6e5262e242c94851e3a5bf8f314b3e5de0e389fc9e5b3eadac030000000009525265655151005153ffffffffdbb53ce99b5a2320a4e6e2d13b01e88ed885a0957d222e508e9ec8e4f83496cb0200000007635200abac63ac04c96237020cc5490100000000080000516a51ac6553074a360200000000025152225520ca", "6551ab65ac65516a", 1, -489869549, "9bc5bb772c553831fb40abe466074e59a469154679c7dee042b8ea3001c20393"], + ["ef3acfd4024defb48def411b8f8ba2dc408dc9ee97a4e8bde4d6cb8e10280f29c98a6e8e9103000000035100513d5389e3d67e075469dfd9f204a7d16175653a149bd7851619610d7ca6eece85a516b2df0300000005516aac6552ca678bdf02f477f003000000000057e45b0300000000055252525252af35c20a", "5165ac53ab", 1, -1900839633, "76949d79915e906f3a8142d4b09b1d210a241602f466b16cd9f5548f6003304f"], + ["ff4468dc0108475fc8d4959a9562879ce4ab4867a419664bf6e065f17ae25043e6016c70480100000000ffffffff02133c6f0400000000000bd0a8020000000004006a520035afa4f6", "51ac65ab", 0, -537664724, "c97ad055e7748ec8ff9822a49c814eb6b7967ea1310c82609ebef112b230ece8"], + ["4e8594d803b1d0a26911a2bcdd46d7cbc987b7095a763885b1a97ca9cbb747d32c5ab9aa91030000000353ac53a0cc4b215e07f1d648b6eeb5cdbe9fa32b07400aa773b9696f582cebfd9930ade067b2b200000000060065abab6500fc99833216b8e27a02defd9be47fafae4e4a97f52a9d2a210d08148d2a4e5d02730bcd460100000004516351ac37ce3ae1033baa55040000000006006a636a63acc63c990400000000025265eb1919030000000005656a6a516a00000000", "", 1, -75217242, "46eabf93d4e3c3d546fdbf4f679da908b3328e31259c19172ff78c507ba62766"], + ["a88830a7023f13ed19ab14fd757358eb6af10d6520f9a54923a6d613ac4f2c11e249cda8aa030000000851630065abababacffffffff8f5fe0bc04a33504c4b47e3991d25118947a0261a9fa520356731eeabd561dd3020000000363ababffffffff038404bd010000000008ab5153516aab6a63d33a5601000000000263004642dc020000000009655152acac636352004be6f3af", "5253536565006aab6a", 0, 1174417836, "2e42ead953c9f4f81b72c27557e6dc7d48c37ff2f5c46c1dbe9778fb0d79f5b2"], + ["44e1a2b4010762af23d2027864c784e34ef322b6e24c70308a28c8f2157d90d17b99cd94a401000000085163656565006300ffffffff0198233d020000000002000000000000", "52525153656365", 0, 1119696916, "3b1c28c02688d9aa99275830320bba8f8c90d30f009733574bd80d1d9a17a85e"], + ["44ca65b901259245abd50a745037b17eb51d9ce1f41aa7056b4888285f48c6f26cb97b7a25020000000552636363abffffffff047820350400000000040053acab14f3e603000000000652635100ab630ce66c03000000000001bdc704000000000765650065ac51ac3e886381", "51", 0, -263340928, "3e4ff56292e2a27853a6703be918ba2659006f60f15d499ef9206cddd64b0b8b"], + ["cfa147d2017fe84122122b4dda2f0d6318e59e60a7207a2d00737b5d89694d480a2c26324b0000000006006351526552ffffffff0456b5b804000000000800516aab525363ab166633000000000004655363ab254c0e02000000000952ab6a6a00ab525151097c1b020000000009656a52ac6300530065ad0d6e50", "6a535165ac6a536500", 0, -574683248, "fa07f739199f8993ae459c401e6a3b40a71f9634649f3d41ea5c1efd080f803a"], + ["91c5d5f6022fea6f230cc4ae446ce040d8313071c5ac1749c82982cc1988c94cb1738aa48503000000016a19e204f30cb45dd29e68ff4ae160da037e5fc93538e21a11b92d9dd51cf0b5efacba4dd70000000005656a6aac51ffffffff03db126905000000000953006a53ab6563636a36a273030000000006656a52656552b03ede00000000000352516500000000", "530052526a00", 1, 1437328441, "255c125b60ee85f4718b2972174c83588ee214958c3627f51f13b5fb56c8c317"], + ["03f20dc202c886907b607e278731ebc5d7373c348c8c66cac167560f19b341b782dfb634cb03000000076a51ac6aab63abea3e8de7adb9f599c9caba95aa3fa852e947fc88ed97ee50e0a0ec0d14d164f44c0115c10100000004ab5153516fdd679e0414edbd000000000005ac636a53512021f2040000000007006a0051536a52c73db2050000000005525265ac5369046e000000000003ab006a1ef7bd1e", "52656a", 0, 1360223035, "5a0a05e32ce4cd0558aabd5d79cd5fcbffa95c07137506e875a9afcba4bef5a2"], + ["d9611140036881b61e01627078512bc3378386e1d4761f959d480fdb9d9710bebddba2079d020000000763536aab5153ab819271b41e228f5b04daa1d4e72c8e1955230accd790640b81783cfc165116a9f535a74c000000000163ffffffffa2e7bb9a28e810624c251ff5ba6b0f07a356ac082048cf9f39ec036bba3d431a02000000076a000000ac65acffffffff01678a820000000000085363515153ac635100000000", "535353", 2, -82213851, "52b9e0778206af68998cbc4ebdaad5a9469e04d0a0a6cef251abfdbb74e2f031"], + ["98b3a0bf034233afdcf0df9d46ac65be84ef839e58ee9fa59f32daaa7d684b6bdac30081c60200000007636351acabababffffffffc71cf82ded4d1593e5825618dc1d5752ae30560ecfaa07f192731d68ea768d0f0100000006650052636563f3a2888deb5ddd161430177ce298242c1a86844619bc60ca2590d98243b5385bc52a5b8f00000000095365acacab520052ac50d4722801c3b8a60300000000035165517e563b65", "51", 1, -168940754, "b53e3c92548a9e5044229334e5905f65b045f536658b8a1e3bb016656adc60a3"], + ["97be4f7702dc20b087a1fdd533c7de762a3f2867a8f439bddf0dcec9a374dfd0276f9c55cc0300000000cdfb1dbe6582499569127bda6ca4aaff02c132dc73e15dcd91d73da77e92a32a13d1a0ba0200000002ab51ffffffff048cfbe202000000000900516351515363ac535128ce0100000000076aac5365ab6aabc84e8302000000000863536a53ab6a6552f051230500000000066aac535153510848d813", "ac51", 0, 229541410, "8f2b51ba291a1a967e501292358a1f7980eb97ce54f309d9e46706de103c194e"], + ["085b6e04040b5bff81e29b646f0ed4a45e05890a8d32780c49d09643e69cdccb5bd81357670100000001abffffffffa5c981fe758307648e783217e3b4349e31a557602225e237f62b636ec26df1a80300000004650052ab4792e1da2930cc90822a8d2a0a91ea343317bce5356b6aa8aae6c3956076aa33a5351a9c0300000004abac5265e27ddbcd472a2f13325cc6be40049d53f3e266ac082172f17f6df817db1936d9ff48c02b000000000152ffffffff021aa7670500000000085353635163ab51ac14d584000000000001aca4d136cc", "6a525300536352536a", 0, -1398925941, "d263338fba96f409b4cf4dc26eec25b82b87cd71cd7159f9aedc501273fc547b"], + ["eec32fff03c6a18b12cd7b60b7bdc2dd74a08977e53fdd756000af221228fe736bd9c42d870100000007005353ac515265ffffffff037929791a188e9980e8b9cc154ad1b0d05fb322932501698195ab5b219488fc02000000070063510065ab6a0bfc176aa7e84f771ea3d45a6b9c24887ceea715a0ff10ede63db8f089e97d927075b4f1000000000551abab63abffffffff02eb933c000000000000262c420000000000036563632549c2b6", "6352", 2, 1480445874, "ff8a4016dfdd918f53a45d3a1f62b12c407cd147d68ca5c92b7520e12c353ff5"], + ["98ea7eac0313d9fb03573fb2b8e718180c70ce647bebcf49b97a8403837a2556cb8c9377f30000000004ac53ac65ffffffff8caac77a5e52f0d8213ef6ce998bedbb50cfdf108954771031c0e0cd2a78423900000000010066e99a44937ebb37015be3693761078ad5c73aa73ec623ac7300b45375cc8eef36087eb80000000007515352acac5100ffffffff0114a51b02000000000000000000", "6aacab", 0, 243527074, "bad77967f98941af4dd52a8517d5ad1e32307c0d511e15461e86465e1b8b5273"], + ["3ab70f4604e8fc7f9de395ec3e4c3de0d560212e84a63f8d75333b604237aa52a10da17196000000000763526a6553ac63a25de6fd66563d71471716fe59087be0dde98e969e2b359282cf11f82f14b00f1c0ac70f02000000050052516aacdffed6bb6889a13e46956f4b8af20752f10185838fd4654e3191bf49579c961f5597c36c0100000005ac636363abc3a1785bae5b8a1b4be5d0cbfadc240b4f7acaa7dfed6a66e852835df5eb9ac3c553766801000000036a65630733b7530218569602000000000952006a6a6a51acab52777f06030000000007ac0063530052abc08267c9", "000000536aac0000", 1, 1919096509, "df1c87cf3ba70e754d19618a39fdbd2970def0c1bfc4576260cba5f025b87532"], + ["bdb6b4d704af0b7234ced671c04ba57421aba7ead0a117d925d7ebd6ca078ec6e7b93eea6600000000026565ffffffff3270f5ad8f46495d69b9d71d4ab0238cbf86cc4908927fbb70a71fa3043108e6010000000700516a65655152ffffffff6085a0fdc03ae8567d0562c584e8bfe13a1bd1094c518690ebcb2b7c6ce5f04502000000095251530052536a53aba576a37f2c516aad9911f687fe83d0ae7983686b6269b4dd54701cb5ce9ec91f0e6828390300000000ffffffff04cc76cc020000000002656a01ffb702000000000253ab534610040000000009acab006565516a00521f55f5040000000000389dfee9", "6a525165", 0, 1336204699, "e052daad5926e591e391869bdf70078d71cb31b045553201fa5d59bb217c47dc"], + ["54258edd017d22b274fbf0317555aaf11318affef5a5f0ae45a43d9ca4aa652c6e85f8a040010000000953ac65ab5251656500ffffffff03321d450000000000085265526a51526a529ede8b030000000003635151ce6065020000000001534c56ec1b", "acac", 0, 2094129948, "099833778a8b826444f1f293cac26f9ffeb701675a3b2312fc8c00db8529e3ab"], + ["ce0d322e04f0ffc7774218b251530a7b64ebefca55c90db3d0624c0ff4b3f03f918e8cf6f60300000003656500ffffffff9cce943872da8d8af29022d0b6321af5fefc004a281d07b598b95f6dcc07b1830200000007abab515351acab8d926410e69d76b7e584aad1470a97b14b9c879c8b43f9a9238e52a2c2fefc2001c56af8010000000400ab5253cd2cd1fe192ce3a93b5478af82fa250c27064df82ba416dfb0debf4f0eb307a746b6928901000000096500abacac6a0063514214524502947efc0200000000035251652c40340100000000096a6aab52000052656a5231c54c", "51", 2, -2090320602, "466dd69a5583987e9a433c7ed0cc1b96ee1036116bfa65dbbff105198ec8a7ab"], + ["47ac54940313430712ebb32004679d3a512242c2b33d549bf5bbc8420ec1fd0850ed50eb6d0300000009536aac6a65acacab51ffffffffb843e44266ce2462f92e6bff54316661048c8c17ecb092cb493b39bfca9117850000000001519ab348c05e74ebc3f67423724a3371dd99e3bceb4f098f8860148f48ad70000313c4c223000000000653006565656512c2d8dc033f3c97010000000002636aa993aa010000000006526365ab526ab7cf560300000000076a0065ac6a526500000000", "005352535300ab6a", 2, 59531927, "45b4e9545aa42d9cc9a55987de747b02acffaee22f9261dacda379896f9097bc"], + ["233cd90b043916fc41eb870c64543f0111fb31f3c486dc72457689dea58f75c16ae59e9eb2000000000500536a6a6affffffff9ae30de76be7cd57fb81220fce78d74a13b2dbcad4d023f3cadb3c9a0e45a3ce000000000965ac6353ac5165515130834512dfb293f87cb1879d8d1b20ebad9d7d3d5c3e399a291ce86a3b4d30e4e32368a9020000000453005165ffffffff26d84ae93eb58c81158c9b3c3cbc24a84614d731094f38d0eea8686dec02824d0300000005636a65abacf02c784001a0bd5d03000000000900655351ab65ac516a416ef503", "", 1, -295106541, "9085246375b88d1b33beb437cb2373675b3f0c23c4eb0b1205cb9425e60ec742"], + ["9200e26b03ff36bc4bf908143de5f97d4d02358db642bd5a8541e6ff709c420d1482d471b70000000008abab65536a636553ffffffff61ba6d15f5453b5079fb494af4c48de713a0c3e7f6454d7450074a2a80cb6d880300000007ac6a00ab5165515dfb7574fbce822892c2acb5d978188b1d65f969e4fe874b08db4c791d176113272a5cc10100000000ffffffff0420958d000000000009ac63516a0063516353dd885505000000000465ac00007b79e901000000000066d8bf010000000005525252006a00000000", "ac5152", 0, 2089531275, "9bb909885399394977b770e9f88e1ff7d5f8c363d507bdce0011c5f4cef1b376"], + ["45f335ba01ce2073a8b0273884eb5b48f56df474fc3dff310d9706a8ac7202cf5ac188272103000000025363ffffffff049d859502000000000365ab6a8e98b1030000000002ac51f3a80603000000000752535151ac00000306e30300000000020051b58b2b3a", "", 0, 1899564574, "78e01310a228f645c23a2ad0acbb8d91cedff4ecdf7ca997662c6031eb702b11"], + ["d8f652a6043b4faeada05e14b81756cd6920cfcf332e97f4086961d49232ad6ffb6bc6c097000000000453526563ffffffff1ea4d60e5e91193fbbc1a476c8785a79a4c11ec5e5d6c9950c668ceacfe07a15020000000352ab51fffffffffe029a374595c4edd382875a8dd3f20b9820abb3e93f877b622598d11d0b09e503000000095351000052ac515152ffffffff9d65fea491b979699ceb13caf2479cd42a354bd674ded3925e760758e85a756803000000046365acabffffffff0169001d00000000000651636a65656300000000", "ab0063630000ac", 3, 1050965951, "4cc85cbc2863ee7dbce15490d8ca2c5ded61998257b9eeaff968fe38e9f009ae"], + ["718662be026e1dcf672869ac658fd0c87d6835cfbb34bd854c44e577d5708a7faecda96e260300000004526a636a489493073353b678549adc7640281b9cbcb225037f84007c57e55b874366bb7b0fa03bdc00000000095165ababac65ac00008ab7f2a802eaa53d000000000007acac516aac526ae92f380100000000056aac00536500000000", "ab00", 1, 43296024, "f6edc292cec21500553555f7ec292f13165002eb91328ef69b7688beba5952d9"], + ["94083c840288d40a6983faca876d452f7c52a07de9268ad892e70a81e150d602a773c175ad03000000007ec3637d7e1103e2e7e0c61896cbbf8d7e205b2ecc93dd0d6d7527d39cdbf6d335789f660300000000ffffffff019e1f7b03000000000800ac0051acac0053539cb363", "", 1, -183614058, "a17b66d6bb427f42653d08207a22b02353dd19ccf2c7de6a9a3a2bdb7c49c9e7"], + ["30e0d4d20493d0cd0e640b757c9c47a823120e012b3b64c9c1890f9a087ae4f2001ca22a61010000000152f8f05468303b8fcfaad1fb60534a08fe90daa79bff51675472528ebe1438b6f60e7f60c10100000009526aab6551ac510053ffffffffaaab73957ea2133e32329795221ed44548a0d3a54d1cf9c96827e7cffd1706df0200000009ab00526a005265526affffffffd19a6fe54352015bf170119742821696f64083b5f14fb5c7d1b5a721a3d7786801000000085265abababac53abffffffff020f39bd030000000004ab6aac52049f6c050000000004ab52516aba5b4c60", "6a6365516a6a655253", 0, -624256469, "c3de3987e0248bf8815fc857138ea80107ed8ce5e60f00ef406678f02eab75f3"], + ["f9c69d940276ec00f65f9fe08120fc89385d7350388508fd80f4a6ba2b5d4597a9e21c884f010000000663ab63ababab15473ae6d82c744c07fc876ecd53bd0f3018b2dbedad77d757d5bdf3811b23d294e8c0170000000001abafababe00157ede2050000000006ac6a5263635300000000", "ab53", 1, 606547088, "714d8b14699835b26b2f94c58b6ea4c53da3f7adf0c62ea9966b1e1758272c47"], + ["5c0ac112032d6885b7a9071d3c5f493aa16c610a4a57228b2491258c38de8302014276e8be030000000300ab6a17468315215262ad5c7393bb5e0c5a6429fd1911f78f6f72dafbbbb78f3149a5073e24740300000003ac5100ffffffff33c7a14a062bdea1be3c9c8e973f54ade53fe4a69dcb5ab019df5f3345050be00100000008ac63655163526aab428defc0033ec36203000000000765516365536a00ae55b2000000000002ab53f4c0080400000000095265516a536563536a00000000", "6a005151006a", 2, 272749594, "91082410630337a5d89ff19145097090f25d4a20bdd657b4b953927b2f62c73b"], + ["e3683329026720010b08d4bec0faa244f159ae10aa582252dd0f3f80046a4e145207d54d31000000000852acac52656aacac3aaf2a5017438ad6adfa3f9d05f53ebed9ceb1b10d809d507bcf75e0604254a8259fc29c020000000653526552ab51f926e52c04b44918030000000000f7679c0100000000090000525152005365539e3f48050000000009516500ab635363ab008396c905000000000253650591024f", "6a6365", 0, 908746924, "458aec3b5089a585b6bad9f99fd37a2b443dc5a2eefac2b7e8c5b06705efc9db"], + ["48c4afb204204209e1df6805f0697edaa42c0450bbbd767941fe125b9bc40614d63d757e2203000000066a5363005152dc8b6a605a6d1088e631af3c94b8164e36e61445e2c60130292d81dabd30d15f54b355a802000000036a6353ffffffff1d05dcec4f3dedcfd02c042ce5d230587ee92cb22b52b1e59863f3717df2362f0300000005536552ac52ffffffffd4d71c4f0a7d53ba47bb0289ca79b1e33d4c569c1e951dd611fc9c9c1ca8bc6c030000000865536a65ab51abacffffffff042f9aa905000000000753655153656351ab93d8010000000002655337440e0300000000005d4c690000000000015278587acb", "ab006565526a51", 0, 1502064163, "bca6f7495882a09d246042eef1379c6f34c34f262837c97cb3001e698e649bd1"], + ["00b20fd104dd59705b84d67441019fa26c4c3dec5fd3b50eca1aa549e750ef9ddb774dcabe000000000651ac656aac65ffffffff52d4246f2db568fc9eea143e4d260c698a319f0d0670f84c9c83341204fde48b0200000000ffffffffb8aeabb85d3bcbc67b132f1fd815b451ea12dcf7fc169c1bc2e2cf433eb6777a03000000086a51ac6aab6563acd510d209f413da2cf036a31b0def1e4dcd8115abf2e511afbcccb5ddf41d9702f28c52900100000006ac52ab6a0065ffffffff039c8276000000000008ab53655200656a52401561010000000003acab0082b7160100000000035100ab00000000", "535265", 1, -947367643, "9751a4f49dd88fe2504a64f1902970d973573c882c2d053fb6f9dc1d0a0bcf21"], + ["455131860220abbaa72015519090a666faf137a0febce7edd49da1eada41feab1505a0028b02000000036365ab453ead4225724eb69beb590f2ec56a7693a608871e0ab0c34f5e96157f90e0a96148f3c502000000085251ab51535163acffffffff022d1249040000000009abac00acac6565630088b310040000000000e3920e59", "5152ab6a52ac5152", 0, 294375737, "c40fd7dfa72321ac79516502500478d09a35cc22cc264d652c7d18b14400b739"], + ["624d28cb02c8747915e9af2b13c79b417eb34d2fa2a73547897770ace08c6dd9de528848d3030000000651ab63abab533c69d3f9b75b6ef8ed2df50c2210fd0bf4e889c42477d58682f711cbaece1a626194bb85030000000765acab53ac5353ffffffff018cc280040000000009abacabac52636352ac6859409e", "ac51ac", 1, 1005144875, "919144aada50db8675b7f9a6849c9d263b86450570293a03c245bd1e3095e292"], + ["8f28471d02f7d41b2e70e9b4c804f2d90d23fb24d53426fa746bcdcfffea864925bdeabe3e0200000001acffffffff76d1d35d04db0e64d65810c808fe40168f8d1f2143902a1cc551034fd193be0e0000000001acffffffff048a5565000000000005005151516afafb610400000000045263ac53648bb30500000000086363516a6a5165513245de01000000000000000000", "6a0053510053", 1, -1525137524, "a25eef66ecef0d1755bc72c815863acea49b3c0016cc4d18f7d3271da479f533"], + ["10ec50d7046b8b40e4222a3c6449490ebe41513aad2eca7848284a08f3069f3352c2a9954f0000000009526aac656352acac53ffffffff0d979f236155aa972472d43ee6f8ce22a2d052c740f10b59211454ff22cb7fd00200000007acacacab63ab53ffffffffbbf97ebde8969b35725b2e240092a986a2cbfd58de48c4475fe077bdd493a20c010000000663ab5365ababffffffff4600722d33b8dba300d3ad037bcfc6038b1db8abfe8008a15a1de2da2264007302000000035351ac6dbdafaf020d0ccf04000000000663ab6a51ab6ae06e5e0200000000036aabab00000000", "", 0, -1658960232, "2420dd722e229eccafae8508e7b8d75c6920bfdb3b5bac7cb8e23419480637c2"], + ["fef98b7101bf99277b08a6eff17d08f3fcb862e20e13138a77d66fba55d54f26304143e5360100000006515365abab00ffffffff04265965030000000004655252ace2c775010000000001002b23b4040000000007516a5153ab53ac456a7a00000000000753ab525251acacba521291", "526aacacab00abab53", 0, -1614097109, "4370d05c07e231d6515c7e454a4e401000b99329d22ed7def323976fa1d2eeb5"], + ["34a2b8830253661b373b519546552a2c3bff7414ea0060df183b1052683d78d8f54e842442000000000152ffffffffd961a8e34cf374151058dfcddc86509b33832bc57267c63489f69ff01199697c0300000002abacba856cfb01b17c2f050000000008515365ac53ab000000000000", "5263ab656a", 1, -2104480987, "2f9993e0a84a6ca560d6d1cc2b63ffe7fd71236d9cfe7d809491cef62bbfad84"], + ["43559290038f32fda86580dd8a4bc4422db88dd22a626b8bd4f10f1c9dd325c8dc49bf479f01000000026351ffffffff401339530e1ed3ffe996578a17c3ec9d6fccb0723dd63e7b3f39e2c44b976b7b0300000006ab6a65656a51ffffffff6fb9ba041c96b886482009f56c09c22e7b0d33091f2ac5418d05708951816ce7000000000551ac525100ffffffff020921e40500000000035365533986f40500000000016a00000000", "52ac51", 0, 1769771809, "02040283ef2291d8e1f79bb71bdabe7c1546c40d7ed615c375643000a8b9600d"], + ["6878a6bd02e7e1c8082d5e3ee1b746cfebfac9e8b97e61caa9e0759d8a8ecb3743e36a30de0100000002ab532a911b0f12b73e0071f5d50b6bdaf783f4b9a6ce90ec0cad9eecca27d5abae188241ddec0200000001651c7758d803f7457b0500000000036551515f4e90000000000001007022080200000000035365acc86b6946", "6351ab", 0, -1929375059, "5d94e9f956ebaab022a2f7f0da86c217aecedac474e1d07b48eb16d9a2cb017c"], + ["35b6fc06047ebad04783a5167ab5fc9878a00c4eb5e7d70ef297c33d5abd5137a2dea9912402000000036aacacffffffff21dc291763419a584bdb3ed4f6f8c60b218aaa5b99784e4ba8acfec04993e50c03000000046a00ac6affffffff69e04d77e4b662a82db71a68dd72ef0af48ca5bebdcb40f5edf0caf591bb41020200000000b5db78a16d93f5f24d7d932f93a29bb4b784febd0cbb1943f90216dc80bba15a0567684b000000000853ab52ab5100006a1be2208a02f6bdc103000000000265ab8550ea04000000000365636a00000000", "", 0, -1114114900, "c66f4c805a11a5c25687ed135f454c0f8be3868fe1eb71db5f7170507de8f97a"], + ["bebb90c302bf91fd4501d33555a5fc5f2e1be281d9b7743680979b65c3c919108cc2f517510100000003abab00ffffffff969c30053f1276550532d0aa33cfe80ca63758cd215b740448a9c08a84826f3303000000056565ab5153ffffffff04bf6f2a04000000000565ab5265ab903e760100000000026a6a7103fa020000000006526553525365b05b2c000000000006ab000000535300000000", "51510053ab63635153", 1, 1081291172, "94338cd47a4639be30a71e21a7103cee4c99ef7297e0edd56aaf57a068b004de"], + ["af48319f031b4eeb4319714a285f44244f283cbff30dcb9275b06f2348ccd0d7f015b54f8500000000066363ac65ac6affffffff2560a9817ebbc738ad01d0c9b9cf657b8f9179b1a7f073eb0b67517409d108180200000005ac6365ab52ffffffff0bdd67cd4ecae96249a2e2a96db1490ee645f042fd9d5579de945e22b799f4d003000000086552ab515153ab00cf187c8202e51abf0300000000066552006a00abadf37d000000000004ac6a535100000000", "63ab65", 1, -1855554510, "dcc7bf42ae7d1c59a43bdf0f83715888891b8a6e874d0a9d27d3e53398f79271"], + ["f35befbc03faf8c25cc4bc0b92f6239f477e663b44b83065c9cb7cf231243032cf367ce3130000000005ab65526a517c4c334149a9c9edc39e29276a4b3ffbbab337de7908ea6f88af331228bd90086a6900ba020000000151279d19950d2fe81979b72ce3a33c6d82ebb92f9a2e164b6471ac857f3bbd3c0ea213b542010000000953ab51635363520065052657c20300a9ba04000000000452636a6a0516ea020000000008535253656365ababcfdd3f01000000000865ac516aac00530000000000", "", 2, -99793521, "c834a5485e68dc13edb6c79948784712122440d7fa5bbaa5cd2fc3d4dac8185d"], + ["d3da18520216601acf885414538ce2fb4d910997eeb91582cac42eb6982c9381589587794f0300000000fffffffff1b1c9880356852e10cf41c02e928748dd8fae2e988be4e1c4cb32d0bfaea6f7000000000465ab6aabffffffff02fb0d69050000000002ababeda8580500000000085163526565ac52522b913c95", "ac", 1, -1247973081, "5d716e5b124c5e82904d262e9ec0f8d65c86dfc02774100d48fdbad2aa048261"], + ["8218eb740229c695c252e3630fc6257c42624f974bc856b7af8208df643a6c520ef681bfd00000000002510066f30f270a09b2b420e274c14d07430008e7886ec621ba45665057120afce58befca96010300000004525153ab84c380a9015d96100000000000076a5300acac526500000000", "ac005263", 0, -1855679695, "5071f8acf96aea41c7518bd1b5b6bbe16258b529df0c03f9e374b83c66b742c6"], + ["1123e7010240310013c74e5def60d8e14dd67aedff5a57d07a24abc84d933483431b8cf8ea0300000003530051fc6775ff1a23c627a2e605dd2560e84e27f4208300071e90f4589e762ad9c9fe8d0da95e020000000465655200ffffffff04251598030000000004ab65ab639d28d90400000000096563636aacac525153474df801000000000851525165ac51006a75e23b040000000000e5bd3a4a", "6363636565", 0, -467124448, "9cb0dd04e9fe287b112e94a1647590d27e8b164ca13c4fe70c610fd13f82c2fd"], + ["fd92fe1003083c5179f97e77bf7d71975788138147adbdb283306802e261c0aee080fa22630200000000860c643ba9a1816b9badf36077b4554d11720e284e395a1121bc45279e148b2064c65e49020000000651ab6a53636a2c713088d20f4bc4001264d972cce05b9fe004dc33376ad24d0d013e417b91a5f1b6734e000000000100ffffffff02e3064c0500000000066552006a5165b86e8705000000000665ab65ab53522052eadb", "00ab53525265", 0, 776203277, "47207b48777727532f62e09afcd4104ea6687e723c7657c30504fa2081331cc8"], + ["d1b6a703038f14d41fcc5cc45455faa135a5322be4bf0f5cbcd526578fc270a236cacb853f0200000001abffffffff135aeff902fa38f202ccf5bd34437ff89c9dc57a028b62447a0a38579383e8ef0000000000ffffffffadf398d2c818d0b90bc474f540c3618a4a643482eeab73d36101987e2ec0335900000000004bd3323504e69fc10000000000055151535251790ada02000000000563ab6aab521337a704000000000963ac63abacac52656a1e9862010000000007656500ac51ab6a8f4ee672", "ab5251656565ac63", 2, 82008330, "8979fdf5f2d0ded1a82d28c85a9c78d90a63def26657de00dd0023afab6f8f73"], + ["81dadaa7011556683db3fe95262f4fdb20391b7e75b7ffcee51b176af64d83c06f85545d620200000005ab5151ab52ffffffff044805ef0300000000065353516352639702c802000000000900516351515252ab5270db08040000000009ac516aab526553abac4aabc90500000000096365ab0052636a525100000000", "6565ab6a5152", 0, -2126294223, "5f992388b98d9dcf8f517c37c196b5731291f3691c5c85768841c80575eeda5e"], + ["3b937e05032b8895d2f4945cb7e3679be2fbd15311e2414f4184706dbfc0558cf7de7b4d000000000001638b91a12668a3c3ce349788c961c26aa893c862f1e630f18d80e7843686b6e1e6fc396310000000000852635353ab65ac51eeb09dd1c9605391258ee6f74b9ae17b5e8c2ef010dc721c5433dcdc6e93a1593e3b6d1700000000085365ac6553526351ffffffff0308b18e04000000000253acb6dd00040000000008536aac5153ac516ab0a88201000000000500ac006500804e3ff2", "", 0, 416167343, "595a3c02254564634e8085283ec4ea7c23808da97ce9c5da7aecd7b553e7fd7f"], + ["a48f27ca047997470da74c8ee086ddad82f36d9c22e790bd6f8603ee6e27ad4d3174ea875403000000095153ac636aab6aacabffffffffefc936294e468d2c9a99e09909ba599978a8c0891ad47dc00ba424761627cef202000000056a51630053ffffffff304cae7ed2d3dbb4f2fbd679da442aed06221ffda9aee460a28ceec5a9399f4e0200000000f5bddf82c9c25fc29c5729274c1ff0b43934303e5f595ce86316fc66ad263b96ca46ab8d0100000003536500d7cf226b0146b00c04000000000200ac5c2014ce", "515100636563", 0, 1991799059, "9c051a7092fe17fa62b1720bc2c4cb2ffc1527d9fb0b006d2e142bb8fe07bf3c"], + ["180cd53101c5074cf0b7f089d139e837fe49932791f73fa2342bd823c6df6a2f72fe6dba1303000000076a6a63ac53acabffffffff03853bc1020000000007ac526a6a6a6a003c4a8903000000000453515163a0fbbd030000000005ab656a5253253d64cf", "ac65", 0, -1548453970, "4d8efb3b99b9064d2f6be33b194a903ffabb9d0e7baa97a48fcec038072aac06"], + ["c21ec8b60376c47e057f2c71caa90269888d0ffd5c46a471649144a920d0b409e56f190b700000000008acac6a526a536365ffffffff5d315d9da8bf643a9ba11299450b1f87272e6030fdb0c8adc04e6c1bfc87de9a0000000000ea43a9a142e5830c96b0ce827663af36b23b0277244658f8f606e95384574b91750b8e940000000007516a63ac0063acffffffff023c61be0400000000055165ab5263313cc8020000000006006a53526551ed8c3d56", "6a", 1, 1160627350, "089c93c868d392f14096bbddb45589878aaaaa384c3f58b604d9927bba350b13"], + ["128cd90f04b66a4cbc78bf48748f6eec0f08d5193ee8d0a6f2e8d3e5f138ed12c2c87d01a301000000085200ab6aac00ab00ffffffff09fc88bb1851e3dfb3d30179c38e15aeb1b39929c7c74f6acd071994ed4806490300000000e7fc5ea12ec56f56c0d758ecf4bb88aa95f3b08176b336db3b9bec2f6e27336dce28adbe030000000400530051fffffffffd6ff1adcf1fbe0d883451ee46904f1b7e8820243d395559b2d4ee8190a6e891000000000080fb1ae702f85b400000000000035200ab8d9651010000000006ab6a52536aab00000000", "ab", 1, 1667598135, "c7bbbf41cb11e72c0de188dceaef4f4a7bea31c52210e6e0fc64fa53d50e218c"], + ["da9695a403493d3511c10e1fe1286f954db0366b7667c91ef18ae4578056c1bf752114ac5901000000035351519788d91dd1f9c62dc005d80ea54eb13f7131ca5aace3d5d29f9b58ccc5fbc9a27e779950010000000453ac6a00ffffffffe2556ff29ebe83eb42a32c7a8d93bc598043578f491b5935805a33608538845a030000000252ab65d21b3b018f26c4030000000006acab51535352e1cbcb10", "006565ab52", 2, -1550927858, "3aab27a9a51b04ef31b552f3d276a6611b363166942ac4223fb54812705513fc"], + ["b240517501334021240427adb0b413433641555424f6d24647211e3e6bfbb22a8045cbda2f000000000071bac8630112717802000000000000000000", "6a5165abac52656551", 0, 1790414254, "2c8be597620d95abd88f9c1cf4967c1ae3ca2309f3afec8928058c9598660e9e"], + ["96bac43903044a199b4b3efeeec5d196ee23fb05495541fa2cd6fb6405a9432d1723363660010000000151ffffffffe6ce2b66ce1488918a3e880bebb0e750123f007c7bcbac8fcd67ce75cb6fbae80300000000ffffffff9c0955aa07f506455834895c0c56be5a095398f47c62a3d431fe125b161d666a0200000005520000abac7ffdbc540216f2f004000000000165a26dce010000000001ab00000000", "5151ab656a656a6a63", 0, -707123065, "26b22e18d5d9081fde9631594a4f7c49069ed2e429f3d08caf9d834f685ccab2"], + ["b8fd394001ed255f49ad491fecc990b7f38688e9c837ccbc7714ddbbf5404f42524e68c18f0000000007ab6353535363ab081e15ee02706f7d050000000008515200535351526364c7ec040000000005636a53acac9206cbe1", "655352ac", 0, -1251578838, "8e0697d8cd8a9ccea837fd798cc6c5ed29f6fbd1892ee9bcb6c944772778af19"], + ["e42a76740264677829e30ed610864160c7f97232c16528fe5610fc08814b21c34eefcea69d010000000653006a6a0052ffffffff647046cf44f217d040e6a8ff3f295312ab4dd5a0df231c66968ad1c6d8f4428000000000025352ffffffff0199a7f900000000000000000000", "655263006a005163", 1, 1122505649, "873fbe592236acdf45a756eb9f86f1d3d3459667a3d573d51503cd43710ad9df"], + ["0f034f32027a8e094119443aa9cfe11737c6d7dda9a52b839bc073dcc0235b847b28e0fab60200000006ac53ac536a63eee63447dfdad80476994b68706e916df1bd9d7cb4f3a4f6b14369de84564bea2e8688bd030000000565636a65acf8434663020b35fe01000000000800abab655163acabb3d6a103000000000353acab345eeda0", "526a51ac63ab51", 1, 66020151, "640924285e6fa7545f66f7d2829544faadff8f92eb460155fee8f7137d0c707f"], + ["a2dfa4690214c1ab25331815a5128f143219de51a47abdc7ce2d367e683eeb93960a31af9f010000000363636affffffff8be0628abb1861b078fcc19c236bc4cc726fa49068b88ad170adb2a97862e7460200000004ac655363ffffffff0441f11103000000000153dbab0c000000000009ab53ac5365526aab63abbb95050000000004ab52516a29a029040000000003ac526a00000000", "6a52ac63", 1, -1302210631, "126ff2fce9af88a93df1e33e51ae43e18d1288d2cc652d63b181edfb80afa24d"], + ["9dbc591f04521670af83fb3bb591c5d4da99206f5d38e020289f7db95414390dddbbeb56680100000004ac5100acffffffffb6a40b5e29d5e459f8e72d39f800089529f0889006cad3d734011991da8ef09d0100000009526a5100acab536a515fc427436df97cc51dc8497642ffc868857ee245314d28b356bd70adba671bd6071301fc0000000000ffffffff487efde2f620566a9b017b2e6e6d42525e4070f73a602f85c6dfd58304518db30000000005516353006a8d8090180244904a0200000000046a65656ab1e9c203000000000451ab63aba06a5449", "", 0, -1414953977, "0a2a186bfb262762e8dd37904c4d8ac212a146764f36e27416c5f9fd56b559be"], + ["1345fb2c04bb21a35ae33a3f9f295bece34650308a9d8984a989dfe4c977790b0c21ff9a7f0000000006ac52ac6a0053ffffffff7baee9e8717d81d375a43b691e91579be53875350dfe23ba0058ea950029fcb7020000000753ab53ab63ab52ffffffff684b6b3828dfb4c8a92043b49b8cb15dd3a7c98b978da1d314dce5b9570dadd202000000086353ab6a5200ac63d1a8647bf667ceb2eae7ec75569ca249fbfd5d1b582acfbd7e1fcf5886121fca699c011d0100000003ac006affffffff049b1eb00300000000001e46dc0100000000080065ab6a6a630065ca95b40300000000030051520c8499010000000006ab6aac526a6500000000", "53526aac636300", 2, 1809978036, "51ee91db5a9b0e3a8ea688f87e7d6a7015612ede8cfd764eba1e826f34cbab59"], + ["7d75dc8f011e5f9f7313ba6aedef8dbe10d0a471aca88bbfc0c4a448ce424a2c5580cda1560300000003ab5152ffffffff01997f8e0200000000096552ac6a65656563530d93bbcc", "00656a6563", 0, 1414485913, "ec91eda1149f75bffb97612569a78855498c5d5386d473752a2c81454f297fa7"], + ["1459179504b69f01c066e8ade5e124c748ae5652566b34ed673eea38568c483a5a4c4836ca0100000008ac5352006563656affffffff5d4e037880ab1975ce95ea378d2874dcd49d5e01e1cdbfae3343a01f383fa35800000000095251ac52ac6aac6500ffffffff7de3ae7d97373b7f2aeb4c55137b5e947b2d5fb325e892530cb589bc4f92abd503000000086563ac53ab520052ffffffffb4db36a32d6e543ef49f4bafde46053cb85b2a6c4f0e19fa0860d9083901a1190300000003ab51531bbcfe5504a6dbda040000000008536a5365abac6500d660c80300000000096565abab6a53536a6a54e84e010000000003acac52df2ccf0500000000025351220c857e", "", 2, 1879181631, "3aad18a209fab8db44954eb55fd3cc7689b5ec9c77373a4d5f4dae8f7ae58d14"], + ["d98b777f04b1b3f4de16b07a05c31d79965579d0edda05600c118908d7cf642c9cd670093f020000000953005351ac65ab5363a268caad6733b7d1718008997f249e1375eb3ab9fe68ab0fe170d8e745ea24f54ce67f9b00000000066500516a5151ffffffff7ef8040dfcc86a0651f5907e8bfd1017c940f51cf8d57e3d3fe78d57e40b1e610200000003535263ffffffff39846cfed4babc098ff465256ba3820c30d710581316afcb67cd31c623b703360300000001acffffffff03d405120100000000056300006a5201a73d050000000004ab636a6a294c8c000000000006ac65536553ac00000000", "63525351abac", 1, 2018694697, "dd81e8ba53fc0f8a5aa6c1ee0b4b52ce75d5b634414da5ebb5caf625b592b287"], + ["cabb1b06045a895e6dcfc0c1e971e94130c46feace286759f69a16d298c8b0f6fd0afef8f20300000004ac006352ffffffffa299f5edac903072bfb7d29b663c1dd1345c2a33546a508ba5cf17aab911234602000000056a65515365ffffffff89a20dc2ee0524b361231092a070ace03343b162e7162479c96b757739c8394a0300000002abab92ec524daf73fabee63f95c1b79fa8b84e92d0e8bac57295e1d0adc55dc7af5534ebea410200000001534d70e79b04674f6f00000000000600abacab53517d60cc0200000000035265ab96c51d040000000004ac6300ac62a787050000000008006a516563ab63639e2e7ff7", "6551ac6351ac", 3, 1942663198, "98b364fd95e4482a1ce52b8ffdb4eb72e5e341e96881736a12eaef807cf2ba8f"], + ["8b96d7a30132f6005b5bd33ea82aa325e2bcb441f46f63b5fca159ac7094499f380f6b7e2e00000000076aacabac6300acffffffff0158056700000000000465005100c319e6d0", "52006a", 0, -1100733537, "c500f40a2023584e93016cdd965a9f57497ec7cba7be8d5fd1b955381ec36d29"], + ["112191b7013cfbe18a175eaf09af7a43cbac2c396f3695bbe050e1e5f4250603056d60910e02000000001c8a5bba03738a22010000000005525352656a77a149010000000002510003b52302000000000351ac52722be8e6", "65ac6565", 0, -1847972801, "57aa807b79e6c7eaa33d69257f336675acd7301cfd3c4d1c3420cecd8f2c518f"], + ["ce6e1a9e04b4c746318424705ea69517e5e0343357d131ad55d071562d0b6ebfedafd6cb840100000003656553ffffffff67bd2fa78e2f52d9f8900c58b84c27ef9d7679f67a0a6f78645ce61b883fb8de000000000100d699a56b9861d99be2838e8504884af4d30b909b1911639dd0c5ad47c557a0773155d4d303000000046a5151abffffffff9fdb84b77c326921a8266854f7bbd5a71305b54385e747fe41af8a397e78b7fa010000000863acac6a51ab00ac0d2e9b9d049b8173010000000007ac53526a650063ba9b7e010000000008526a00525263acac0ab3fd030000000000ea8a0303000000000200aca61a97b9", "", 1, -1276952681, "b6ed4a3721be3c3c7305a5128c9d418efa58e419580cec0d83f133a93e3a22c5"], + ["a7721d94021652d90c79aaf5022d98219337d50f836382403ed313adb1116ba507ac28b0b0010000000551ac6300ab89e6d64a7aa81fb9595368f04d1b36d7020e7adf5807535c80d015f994cce29554fe869b01000000065353ab636500ffffffff024944c90100000000046300635369df9f01000000000000000000", "656a536551ab", 0, -1740151751, "810f1c2bcd7e478a7f76191b2b90def73c20736a786ea587d5b7d7affc0af713"], + ["2f7353dd02e395b0a4d16da0f7472db618857cd3de5b9e2789232952a9b154d249102245fd030000000151617fd88f103280b85b0a198198e438e7cab1a4c92ba58409709997cc7a65a619eb9eec3c0200000003636aabffffffff0397481c0200000000045300636a0dc97803000000000009d389030000000003ac6a53134007bb", "0000536552526a", 0, -1912746238, "fdd4d417377bd8924ffc9b0d4cfa25ddb4a2ffcef787dd33e48ce475d70c0734"], + ["7d95473604fd5267d0e1bb8c9b8be06d7e83ff18ad597e7a568a0aa033fa5b4e1e2b6f1007020000000465006a6affffffffaee008503bfc5708bd557c7e78d2eab4878216a9f19daa87555f175490c40aaf000000000263abffffffffabd74f0cff6e7ceb9acc2ee25e65af1abcebb50c08306e6c78fa8171c37613dd010000000552acacababffffffff54a3069393f7930fa1b331cdff0cb945ec21c11d4605d8eedba1d3e094c6ae1f01000000026300ffffffff0182edeb050000000009526353ab5153530065a247e8cd", "51516aab00", 2, -426210430, "2707ca714af09494bb4cf0794abe33c6cba5f29891d619e76070269d1fa8e690"], + ["221d4718023d9ca9fe1af178dbfce02b2b369bf823ea3f43f00891b7fef98e215c06b94fdd000000000951005153ab000051acffffffffb1c7ad1c64b7441bf5e70cd0f6eb4ec96821d67fc4997d9e6dfdceadecd36dde01000000070051536a635153ffffffff04e883cd00000000000851ab536553ab0052bbb2f70400000000002f1b2e03000000000165259fcb00000000000010dbde99", "ab", 1, 665721216, "42919e9ffae7d46527331243023b403f9c7a8c2cd4e3fffd00d18b198bd6ae76"], + ["6f66c0b3013e6ae6aabae9382a4326df31c981eac169b6bc4f746edaa7fc1f8c796ef4e374000000000665ab6aabac6affffffff0191c8d6030000000002525300000000", "6a5352516a635352ab", 0, -1299629906, "48411efeb133c6b7fec4e7bdbe613f827093cb06ea0dbcc2ffcfde3a9ac4356c"], + ["89e7928c04363cb520eff4465251fd8e41550cbd0d2cdf18c456a0be3d634382abcfd4a2130200000006ac516a6a656355042a796061ed72db52ae47d1607b1ceef6ca6aea3b7eea48e7e02429f382b378c4e51901000000085351ab6352ab5252ffffffff53631cbda79b40183000d6ede011c778f70147dc6fa1aed3395d4ce9f7a8e69701000000096a6553ab52516a52abad0de418d80afe059aab5da73237e0beb60af4ac490c3394c12d66665d1bac13bdf29aa8000000000153f2b59ab6027a33eb040000000007005351ac5100ac88b941030000000003ab0052e1e8a143", "63656a", 0, 1258533262, "2f9282fb0e8622867194b50efbc59d61aee80db618619088785bc59348e7ca3e"], + ["ca356e2004bea08ec2dd2df203dc275765dc3f6073f55c46513a588a7abcc4cbde2ff011c7020000000553525100003aefec4860ef5d6c1c6be93e13bd2d2a40c6fb7361694136a7620b020ecbaca9413bcd2a030000000965ac00536352535100ace4289e00e97caaea741f2b89c1143060011a1f93090dc230bee3f05e34fbd8d8b6c399010000000365526affffffff48fc444238bda7a757cb6a98cb89fb44338829d3e24e46a60a36d4e24ba05d9002000000026a53ffffffff03d70b440200000000056a6a526aac853c97010000000002515335552202000000000351635300000000", "0052", 3, -528192467, "fc93cc056c70d5e033933d730965f36ad81ef64f1762e57f0bc5506c5b507e24"], + ["82d4fa65017958d53e562fac073df233ab154bd0cf6e5a18f57f4badea8200b217975e31030200000004636aab51ac0891a204227cc9050000000006635200655365bfef8802000000000865650051635252acfc2d09050000000006ab65ac51516380195e030000000007ac52525352510063d50572", "53", 0, -713567171, "e095003ca82af89738c1863f0f5488ec56a96fb81ea7df334f9344fcb1d0cf40"], + ["75f6949503e0e47dd70426ef32002d6cdb564a45abedc1575425a18a8828bf385fa8e808e600000000036aabab82f9fd14e9647d7a1b5284e6c55169c8bd228a7ea335987cef0195841e83da45ec28aa2e0300000002516350dc6fe239d150efdb1b51aa288fe85f9b9f741c72956c11d9dcd176889963d699abd63f0000000001ab429a63f502777d20010000000007abac52ac516a53d081d9020000000003acac630c3cc3a8", "535152516551510000", 1, 973814968, "c6ec1b7cb5c16a1bfd8a3790db227d2acc836300534564252b57bd66acf95092"], + ["24f24cd90132b2162f938f1c22d3ca5e7daa83515883f31a61a5177aebf99d7db6bdfc398c010000000163ffffffff01d5562d0100000000016300000000", "5265ac5165ac5252ab", 0, 1055129103, "5eeb03e03806cd7bfd44bbba69c30f84c2c5120df9e68cd8facc605fcfbc9693"], + ["5ff2cac201423064a4d87a96b88f1669b33adddc6fa9acdc840c0d8a243671e0e6de49a5b00300000005ac6353655353b91db50180db5a03000000000663535151006a047a3aff", "52ab51ab5365005163", 0, -1336626660, "7fede1cb4d40cb6cc184643d0d1b3f317e71d9893782a6fa8de0da0bbeb6f1be"], + ["10011f150220ad76a50ccc7bb1a015eda0ff987e64cd447f84b0afb8dc3060bdae5b36a6900200000000ffffffff1e92dd814dfafa830187bc8e5b9258de2445ec07b02c420ee5181d0b203bb334000000000565ab536a65ffffffff0124e65401000000000800ab636553ab53ac00000000", "53abab0051", 0, 440222748, "c6675bf229737e005b5c8ffa6f81d9e2c4396840921b6151316f67c4315a4270"], + ["8b95ec900456648d820a9b8df1d8f816db647df8a8dc9f6e7151ebf6079d90ee3f6861352a02000000085200ab00ac535151ffffffff039b10b845f961225ac0bcaac4f5fe1991029a051aa3d06a3811b5762977a67403000000035252abffffffff8559d65f40d5e261f45aec8aad3d2c56c6114b22b26f7ee54a06f0881be3a7f5010000000765635252536363ffffffff38f8b003b50f6412feb2322b06b270197f81ad69c36af02ca5008b94eee5f650020000000165ffffffff01ae2b00010000000001638eb153a2", "0053ab5300ac53", 2, 1266056705, "171dfedc2648fcd6acfe12ea19269cd45c441be2ab19b40dd148a97e03c5cd45"], + ["babbb7ea01ab5d584727cb44393b17cf66521606dc81e25d85273be0d57bad43e8f6b6d43501000000036a656aba83a68803fb0f4a000000000005536353ab633fcfe4020000000009ac00acab6351006a65182a0c03000000000453ac5363bee74f44", "536a6a6a6365ac51ab", 0, -799187689, "f754ccbc3e9a08d3925681dc32dbdff7047cd6d33c70f0ec1b765260cad7aefa"], + ["e86a24bc03e4fae784cdf81b24d120348cb5e52d937cd9055402fdba7e43281e482e77a1c100000000046363006affffffffa5447e9bdcdab22bd20d88b19795d4c8fb263fbbf7ce8f4f9a85f865953a6325020000000663ac53535253ffffffff9f8b693bc84e0101fc73748e0513a8cecdc264270d8a4ee1a1b6717607ee1eaa00000000026a513417bf980158d82c020000000009005253005351acac5200000000", "6353516365536a6a", 2, -563792735, "508129278ef07b43112ac32faf00170ad38a500eed97615a860fd58baaad174b"], + ["53bd749603798ed78798ef0f1861b498fc61dcee2ee0f2b37cddb115b118e73bc6a5a47a0201000000096a63656a6aab6a000007ff674a0d74f8b4be9d2e8e654840e99d533263adbdd0cf083fa1d5dd38e44d2d163d900100000007abab5251ac6a51c8b6b63f744a9b9273ccfdd47ceb05d3be6400c1ed0f7283d32b34a7f4f0889cccf06be30000000009516a52636551ab516a9ac1fe63030c677e05000000000027bc610000000000086565636a635100526e2dc60200000000015300000000", "6552536a515351ab", 1, -1617066878, "fe516df92299e995b8e6489be824c6839543071ec5e9286060b2600935bf1f20"], + ["691bf9fc028ca3099020b79184e70039cf53b3c7b3fe695d661fd62d7b433e65feda2150610000000003ac63abffffffff2c814c15b142bc944192bddccb90a392cd05b968b599c1d8cd99a55a28a243fd0100000009ab5300526a5200abac98516a5803dfd3540500000000046552ac522838120100000000040053ab6a4409a903000000000665636a5300658759621b", "65ac5165ab", 0, -359941441, "d582c442e0ecc400c7ba33a56c93ad9c8cfd45af820350a13623594b793486f0"], + ["536bc5e60232eb60954587667d6bcdd19a49048d67a027383cc0c2a29a48b960dc38c5a0370300000005ac636300abffffffff8f1cfc102f39b1c9348a2195d496e602c77d9f57e0769dabde7eaaedf9c69e250100000006acabab6a6351ffffffff0432f56f0400000000046a5365517fd54b0400000000035265539484e4050000000003536a5376dc25020000000008ac536aab6aab536ab978e686", "ac0051006a006a006a", 0, -273074146, "f70a1ce9dd45aa55ae0a93f9d0e43b1a8dbeec81501abdaad02931586dc34c40"], + ["74606eba01c2f98b86c29ba5a32dc7a7807c2abe6ed8d89435b3da875d87c12ae05329e6070200000003510052ffffffff02a1e2c4020000000006516563526a63c68bae04000000000952ab6363ab00006363fe19ae4f", "63ababacac5365", 0, 112323336, "4bd95cc065e9449002f04e8418566bb4de936d1aa9e10f8f64b3a8f8cc262001"], + ["2ed805e20399e52b5bcc9dc075dad5cf19049ff5d7f3de1a77aee9288e59c5f4986751483f020000000165ffffffff967531a5726e7a653a9db75bd3d5208fa3e2c5e6cd5970c4d3aba84eb644c72c0300000000ffffffffd79030d20c65e5f8d3c55b5692e5bdaa2ae78cfa1935a0282efb97515feac43f030000000400006365261ab88c02bdf66a000000000003ab6351d6ad8b000000000005525152abac00000000", "630053ab5265", 0, 2072814874, "2bd90ee8b8bf8aad0688a5f07842dd65daae1f53d621d3a2e5abae7c248bc60e"], + ["fab796ee03f737f07669160d1f1c8bf0800041157e3ac7961fea33a293f976d79ce49c02ab0200000003ac5252eb097ea1a6d1a7ae9dace338505ba559e579a1ee98a2e9ad96f30696d6337adcda5a85f403000000096500abab656a6a656396d5d41a9b11f571d91e4242ddc0cf2420eca796ad4882ef1251e84e42b930398ec69dd80100000005526551ac6a8e5d0de804f763bb0400000000015288271a010000000001acf2bf2905000000000300ab51c9641500000000000952655363636365ac5100000000", "00ac536552", 0, -1854521177, "20c36c7968ddf255f7c10f25e5dce5d7fe760c78a1a4fcc4e8fac291c26dcbe4"], + ["f2b539a401e4e8402869d5e1502dbc3156dbce93583f516a4947b333260d5af1a34810c6a00200000003525363ffffffff01d305e2000000000005acab535200a265fe77", "", 0, -1435650520, "55219d3ec6eee772685b80bd3fc31cbd9fffdec1562fd70a7b454f3c381a4eaf"], + ["9f10b1d8033aee81ac04d84ceee0c03416a784d1017a2af8f8a34d2f56b767aea28ff88c8f02000000025352ffffffff748cb29843bea8e9c44ed5ff258df1faf55fbb9146870b8d76454786c4549de100000000016a5ba089417305424d05112c0ca445bc7107339083e7da15e430050d578f034ec0c589223b0200000007abac53ac6565abffffffff025a4ecd010000000006636563ab65ab40d2700000000000056a6553526333fa296c", "", 0, -395044428, "7b7bbfcd4ae4a3cd3e63c319c981f9a295ba2c07e004cc2b119abe9dad7152be"], + ["ab81755f02b325cbd2377acd416374806aa51482f9cc5c3b72991e64f459a25d0ddb52e66703000000036a00ab8727056d48c00cc6e6222be6608c721bc2b1e69d0ffbadd51d131f05ec54bcd83003aac5000000000003f2cdb60454630e020000000007526aac63000000e9e25c040000000003516a0088c97e0000000000076a535265655263771b5805000000000851ab00ac6565515100000000", "5151ab00ac", 0, -230931191, "cc03c2631a1aac7266560ddddfc73d7cbb2a1a11ba3a2ae424522a963736f882"], + ["7a17e0ef0378dab4c601240639139335da3b7d684600fa682f59b7346ef39386fe9abd69350000000004ac5252ab807f26fb3249326813e18260a603b9ad66f41f05eaa8146f66bcca452162a502aac4aa8b02000000026a534ea460faa7e3d7854ec6c70d7e797025697b547ec500b2c09c873b4d5517767d3f3720660300000000ffffffff01b12e7a02000000000900ab006aab65656a63991c03e2", "6aab6a", 1, -1577994103, "62cd3413d9d819fb7355336365cf8a2a997f7436cc050a7143972044343b3281"], + ["ff2ecc09041b4cf5abb7b760e910b775268abee2792c7f21cc5301dd3fecc1b4233ee70a2c0200000009acac5300006a51526affffffffeb39c195a5426afff38379fc85369771e4933587218ef4968f3f05c51d6b7c92000000000165453a5f039b8dbef7c1ffdc70ac383b481f72f99f52b0b3a5903c825c45cfa5d2c0642cd50200000001654b5038e6c49daea8c0a9ac8611cfe904fc206dad03a41fb4e5b1d6d85b1ecad73ecd4c0102000000096a51000053ab656565bdb5548302cc719200000000000452655265214a3603000000000300ab6a00000000", "52516a006a63", 1, -2113289315, "3d9a9338f5ecff9f583dc0fe4999ec9373f134e0efd369a6cbf1bcc6735a5119"], + ["70a8577804e553e462a859375957db68cfdf724d68caeacf08995e80d7fa93db7ebc04519d02000000045352ab53619f4f2a428109c5fcf9fee634a2ab92f4a09dc01a5015e8ecb3fc0d9279c4a77fb27e900000000006ab6a51006a6affffffff3ed1a0a0d03f25c5e8d279bb5d931b7eb7e99c8203306a6c310db113419a69ad010000000565516300abffffffff6bf668d4ff5005ef73a1b0c51f32e8235e67ab31fe019bf131e1382050b39a630000000004536a6563ffffffff02faf0bb00000000000163cf2b4b05000000000752ac635363acac15ab369f", "ac", 0, -1175809094, "a14f45741a62c344c93df9484a1e7702c0b4f67952e36b5162ac6f70d50f9a3e"], + ["a3604e5304caa5a6ba3c257c20b45dcd468f2c732a8ca59016e77b6476ac741ce8b16ca8360200000004acac6553ffffffff695e7006495517e0b79bd4770f955040610e74d35f01e41c9932ab8ccfa3b55d0300000007ac5253515365acffffffff6153120efc5d73cd959d72566fc829a4eb00b3ef1a5bd3559677fb5aae116e38000000000400abab52c29e7abd06ff98372a3a06227386609adc7665a602e511cadcb06377cc6ac0b8f63d4fdb03000000055100acabacffffffff04209073050000000009ab5163ac525253ab6514462e05000000000952abacab636300656a20672c0400000000025153b276990000000000056565ab6a5300000000", "5351", 0, 1460890526, "a4aa4458ae079527b9ed223c615880fe5d998a4f6d875cb9683f6762adce839f"], + ["c6a72ed403313b7d027f6864e705ec6b5fa52eb99169f8ea7cd884f5cdb830a150cebade870100000009ac63ab516565ab6a51ffffffff398d5838735ff43c390ca418593dbe43f3445ba69394a6d665b5dc3b4769b5d700000000075265acab515365ffffffff7ee5616a1ee105fd18189806a477300e2a9cf836bf8035464e8192a0d785eea3030000000700ac6a51516a52ffffffff018075fd0000000000015100000000", "005251acac5252", 2, -656067295, "2cc1c7514fdc512fd45ca7ba4f7be8a9fe6d3318328bc1a61ae6e7675047e654"], + ["93c12cc30270fc4370c960665b8f774e07942a627c83e58e860e38bd6b0aa2cb7a2c1e060901000000036300abffffffff4d9b618035f9175f564837f733a2b108c0f462f28818093372eec070d9f0a5440300000001acffffffff039c2137020000000001525500990100000000055265ab636a07980e0300000000005ba0e9d1", "656a5100", 1, 18954118, "3e6f53546a7c6e305b1b05fd1029116fa4533f8ee02910a73eebeb091f9c788d"], + ["97bddc63015f1767619d56598ad0eb5c7e9f880b24a928fea1e040e95429c930c1dc653bdb0100000008ac53acac00005152aaa94eb90235ed10040000000000287bdd0400000000016a8077673a", "acac6a536352655252", 0, -813649781, "5990b139451847343c9bb89cdba0e6daee6850b60e5b7ea505b04efba15f5d92"], + ["cc3c9dd303637839fb727270261d8e9ddb8a21b7f6cbdcf07015ba1e5cf01dc3c3a327745d0300000000d2d7804fe20a9fca9659a0e49f258800304580499e8753046276062f69dbbde85d17cd2201000000096352536a520000acabffffffffbc75dfa9b5f81f3552e4143e08f485dfb97ae6187330e6cd6752de6c21bdfd21030000000600ab53650063ffffffff0313d0140400000000096565515253526aacac167f0a040000000008acab00535263536a9a52f8030000000006abab5151ab63f75b66f2", "6a635353636a65ac65", 1, 377286543, "1e5e49d5097745b4b00d2d9bea0185a5762b256e094d16d1e97cd91cd550f68e"], + ["236f91b702b8ffea3b890700b6f91af713480769dda5a085ae219c8737ebae90ff25915a3203000000056300ac6300811a6a10230f12c9faa28dae5be2ebe93f37c06a79e76214feba49bb017fb25305ff84eb020000000100ffffffff041e351703000000000351ac004ff53e050000000003ab53636c1460010000000000cb55f701000000000651520051ab0000000000", "acac636a6aac5300", 0, 406448919, "793a3d3c37f6494fab79ff10c16702de002f63e34be25dd8561f424b0ea938c4"], + ["22e10d2003ab4ea9849a2801921113583b7c35c3710ff49a6003489395789a7cfb1e6051900100000006526a65535151ffffffff82f21e249ec60db33831d33b9ead0d56f6496db64337dcb7f1c3327c47729c4a020000000253abffffffff138f098f0e6a4cf51dc3e7a3b749f487d1ebde71b73b731d1d02ad1180ac7b8c02000000036563acda215011027a9484020000000007635165530000ac4bf6cb0400000000066aacabab65ab3ce3f32c", "ab0052ab", 2, 1136359457, "b5bd080bbcb8cd652f440484311d7a3cb6a973cd48f03c5c00fd6beb52dfc061"], + ["c47d5ad60485cb2f7a825587b95ea665a593769191382852f3514a486d7a7a11d220b62c54000000000663655253acab8c3cf32b0285b040e50dcf6987ddf7c385b3665048ad2f9317b9e0c5ba0405d8fde4129b00000000095251ab00ac65635300ffffffff549fe963ee410d6435bb2ed3042a7c294d0c7382a83edefba8582a2064af3265000000000152fffffffff7737a85e0e94c2d19cd1cde47328ece04b3e33cd60f24a8a345da7f2a96a6d0000000000865ab6a0051656aab28ff30d5049613ea020000000005ac51000063f06df1050000000008ac63516aabac5153afef5901000000000700656500655253688bc00000000000086aab5352526a53521ff1d5ff", "51ac52", 2, -1296011975, "98815eca0edc0b79ec47be783f179cb4f77cbfdde55583394a01c1d968ff43e6"], + ["0b43f122032f182366541e7ee18562eb5f39bc7a8e5e0d3c398f7e306e551cdef773941918030000000863006351ac51acabffffffffae586660c8ff43355b685dfa8676a370799865fbc4b641c5a962f0849a13d8250100000005abab63acabffffffff0b2b6b800d8e77807cf130de6286b237717957658443674df047a2ab18e413860100000008ab6aac655200ab63ffffffff04f1dbca03000000000800635253ab656a52a6eefd0300000000036365655d8ca90200000000005a0d530400000000015300000000", "65ac65acac", 0, 351448621, "52e95aa6acf02d34a34239b1828d5297ade037867f7f8eb2edbba6684d378438"], + ["4b0ecc0c03ba35700d2a30a71f28e432ff6ac7e357533b49f4e97cf28f1071119ad6b97f3e0300000008acab516363ac63acffffffffcd6a2019d99b5c2d639ddca0b1aa5ea7c1326a071255ea226960bd88f45ca57d00000000085253655363005353ffffffffba257635191c9f216de3277be548cb5a2313114cb1a4c563b03b4ef6c0f4f7040300000001abda542edf0495cdc40100000000026353c049e903000000000752516a53ab65512b0f9304000000000963ab516aac65516552fa9ece050000000009acab6500005152530000000000", "65ab51525352510052", 1, -1355414654, "6efd0c5efdcd05ee6236ec6f38969bcb7cfde2d2c5de5c94951f90df7455004f"], + ["adaac0a803f66811346271c733036d6e0d45e15a9b602092e2e04ad93564f196e7f020b088000000000600526a636a00700ec3f9db07a3a6ce910bf318c7ec87a876e1f2a3366cc69f20cde09203b99c1cb9d15800000000050000ac636a4d0de554ebe95c6cc14faf5ff6361d1deba9474b8b0fd3b93c011cd96aec783abb3f36830200000005ab65005251ffffffff0464eb10050000000007520000ab6a65ab1beaa80300000000005a2f31050000000006526aab65ac52ba7db10000000000045251ab6a0cfb46e7", "ab0051ac52636a", 1, -184733780, "bf6b09b8d35507fd3c7c07f21caac128dc4d4ecef7ff3630b49d326264e51351"], + ["af1c4ab301ec462f76ee69ba419b1b2557b7ded639f3442a3522d4f9170b2d6859765c3df402000000016affffffff01a5ca6c000000000008ab52536aab00005300000000", "6a6351", 0, 110304538, "38c15e4123192b6606c4e2c524e73e1ccb4c3ab3d6f8e1c161cd50bd47d3bc63"], + ["0bfd34210451c92cdfa02125a62ba365448e11ff1db3fb8bc84f1c7e5615da40233a8cd368010000000252ac9a070cd88dec5cf9aed1eab10d19529720e12c52d3a21b92c6fdb589d056908e43ea910e0200000009ac516a52656a6a5165ffffffffc3edcca8d2f61f34a5296c405c5f6bc58276416c720c956ff277f1fb81541ddd00000000030063abffffffff811247905cdfc973d179c03014c01e37d44e78f087233444dfdce1d1389d97c302000000065163000063ab1724a26e02ca37c902000000000851ab53525352ac529012a90100000000085200525253535353fa32575b", "5352ac6351", 1, -1087700448, "b8f1e1f35e3e1368bd17008c756e59cced216b3c699bcd7bebdb5b6c8eec4697"], + ["2c84c0640487a4a695751d3e4be48019dbaea85a6e854f796881697383ea455347d2b2769001000000055265526500ffffffff6aac176d8aa00778d496a7231eeb7d3334f20c512d3db1683276402100d98de5030000000700536a5263526ac1ee9ceb171c0c984ebaf12c234fd1487fbf3b3d73aa0756907f26837efba78d1bed33200300000001ab4d9e8ec0bed837cb929bbed76ee848959cec59de44bd7667b7631a744f880d5c71a20cfd0100000007005363515300abffffffff023753fb0000000000036565532d3873050000000009005152ab6a63acab5200000000", "ab650053ab", 0, -877941247, "4faf0eefb1ae7d75ff22368d4ec38a2843c5c2eb85577f0b8d9088ebc14d5eb9"], + ["1f7e4b1b045d3efa6cd7a11d7873a8bab886c19bd11fcb6712f0948f2db3a7be76ff76c8f100000000095265ab6a0065ac5363ffffffffdaafcfa6029336c997680a541725190f09a6f6da21e54560eca4b5b8ae987da1000000000952ac52acac52515165ffffffff825a38d3b1e5bb4d10f33653ab3ab6882c7abdaec74460257d1528ce7be3f98e0100000007526a006a656a63c14adc8f04953a5d3d3f89237f38b857dd357713896d36215f7e8b77b11d98ea3cdc93df02000000015212484f6104bfafae0300000000025263a2b0120000000000056563ab00516c4d2605000000000653ac6500655301cc93030000000002acab14643b1f", "63acac53ab", 0, 333824258, "18da6ceb011cd36f15ad7dd6c55ef07e6f6ed48881ce3bb31416d3c290d9a0e9"], + ["467a3e7602e6d1a7a531106791845ec3908a29b833598e41f610ef83d02a7da3a1900bf2960000000005ab6a636353ffffffff031db6dac6f0bafafe723b9199420217ad2c94221b6880654f2b35114f44b1df010000000965ab52636a63ac6352ffffffff02b3b95c0100000000026300703216030000000001ab3261c0aa", "6a", 0, 2110869267, "3078b1d1a7713c6d101c64afe35adfae0977a5ab4c7e07a0b170b041258adbf2"], + ["8713bc4f01b411149d575ebae575f5dd7e456198d61d238695df459dd9b86c4e3b2734b62e0300000004abac6363ffffffff03b58049050000000002ac653c714c04000000000953656a005151526a527b5a9e03000000000652ac5100525300000000", "52", 0, -647281251, "0e0bed1bf2ff255aef6e5c587f879ae0be6222ab33bd75ee365ec6fbb8acbe38"], + ["f2ba8a8701b9c401efe3dd0695d655e20532b90ac0142768cee4a3bb0a89646758f544aa8102000000036a52527899f4e4040c6f0b030000000008636565ab530051ab52b60c000000000009515200ab630053ac53a49c5f040000000008ab53ab516300ab63fa27340300000000015100000000", "ac63abab5251", 0, -1328936437, "ab61497afd39e61fe06bc5677326919716f9b20083c9f3417dcea905090e0411"], + ["b5a7df6102107beded33ae7f1dec0531d4829dff7477260925aa2cba54119b7a07d92d5a1d02000000046a516a52803b625c334c1d2107a326538a3db92c6c6ae3f7c3516cd90a09b619ec6f58d10e77bd6703000000056563006a63ffffffff0117484b03000000000853acab52526a65abc1b548a1", "ac006a525100", 0, 2074359849, "14f8a517d8e39e69f6c82fb1838115fcc94fe6d08b868d3e7eb2186d126351b9"], + ["278cb16204b9dadf400266106392c4aa9df01ba03af988c8139dae4c1818ac009f13fc5f1a00000000065200ac656a52ffffffffd006bbebd8cbd7bdead24cddc9badfcc6bc0c2e63c037e5c29aa858f5d0f3e7d01000000046a0051acffffffffbc62a5f57e58da0b67956003ae81ac97cb4cbd1d694c914fc41515c008c4d8fd020000000165e329c844bcc16164be64b64a81cbf4ffd41ed2934e0daa0040ccb8365bab0b2a9e401c180300000003ab52abffffffff02588460030000000000a25a12030000000005535100005300000000", "6553ab6a5300acab51", 3, 989407546, "1c29f110576f4a3b257f67454d99dfc0dee62ef5517ca702848ce4bd2ea1a1d7"], + ["49eb2178020a04fca08612c34959fd41447319c190fb7ffed9f71c235aa77bec28703aa1820200000003ac6353abaff326071f07ec6b77fb651af06e8e8bd171068ec96b52ed584de1d71437fed186aecf0300000001acffffffff03da3dbe02000000000652ac63ac6aab8f3b680400000000096a536a65636a53516a5175470100000000016500000000", "6a536365", 0, 1283691185, "1fd241e3e8511826ed6e37487b9ed045493ac607acb5f8dbd1667e39f845ebaf"], + ["0f96cea9019b4b3233c0485d5b1bad770c246fe8d4a58fb24c3b7dfdb3b0fd90ea4e8e947f0300000006006a5163515303571e1e01906956030000000005ab635353abadc0fbbe", "acac", 0, -1491469027, "716a8180e417228f769dcb49e0491e3fda63badf3d5ea0ceeac7970d483dd7e2"], + ["9a7d858604577171f5fe3f3fd3e5e039c4b0a06717a5381e9977d80e9f53e025e0f16d2877020000000752636565536353ffffffff5862bd028e8276e63f044be1dddcbb8d0c3fa097678308abf2b0f45104a93dbd0100000001531200667ba8fdd3b28e98a35da73d3ddfe51e210303d8eb580f923de988ee632d77793892030000000752526363526563ffffffffe9744eb44db2658f120847c77f47786d268c302120d269e6004455aa3ea5f5e20200000009ab6300636aab656551ffffffff03c61a3c020000000009ab516a6aab6aab53ab737f1a05000000000853acabab655365ab92a4a00400000000016367edf6c8", "535352ab", 3, 659348531, "73f4e7bdf019297e917eba38b48f582bf61227462726e2948a60cf3bf480502a"], + ["148e68480196eb52529af8e83e14127cbfdbd4a174e60a86ac2d86eac9665f46f4447cf7aa01000000045200ac538f8f871401cf240c0300000000065252ab52656a5266cf61", "", 0, -344314825, "eacc47c5a53734d6ae3aedbc6a7c0a75a1565310851b29ef0342dc4745ceb607"], + ["e2bc29d4013660631ba14ecf75c60ec5e9bed7237524d8c10f66d0675daa66d1492cb834530200000004ac510065e42d0c9e04f2b26c01000000000951525152acac65ababa35b7504000000000953ac6aac00650053ab94688c0400000000056365526553a1bced0300000000016a00000000", "65ab0063655353", 0, -888431853, "97ac4f844cf2da95d57cf8d69c8f2eff20e9cf7a4399cc0a5fb99b6f3f69feb9"], + ["0c8a70d70494dca6ab05b2bc941b5b431c43a292bd8f2f02eab5e240a408ca73a676044a4103000000056a51ab006affffffff84496004e54836c035821f14439149f22e1db834f315b24588ba2f031511926c0100000000ffffffffbbc5e70ed1c3060ba1bfe99c1656a3158a7307c3ce8eb362ec32c668596d2bd30000000009636563635351abab00b039344c6fc4f9bec24322e45407af271b2d3dfec5f259ee2fc7227bc5285e22b3be85b40100000009ac00ab53abac6a5352e5ddfcff02d50231020000000005006a51536ab086d9020000000006ababac51ac6a00000000", "abab636565acac6a", 3, 241546024, "24b35150d86020961366024511435aaed01f36fd9a409d903e8ea67e388d7e08"], + ["f98f79cf0274b745e1d6f36da7cbe205a79132a7ad462bdc434cfb1dcd62a6977c3d2a5dbc010000000553516a5365ffffffff4f89f485b53cdad7fb80cc1b7e314b9735b9383bc92c1248bb0e5c6173a55c0d010000000353655293f9b014045ad96d02000000000963ac526a53ac636365f4c27904000000000952536563635152526a2788f0030000000002516aff5add01000000000863530051655351abd04716ba", "ab6552536a53", 1, -2128899945, "56d29f5e300ddfed2cd8dcce5d79826e193981d0b70dc7487772c8a0b3b8d7b1"], + ["6c7913f902aa3f5f939dd1615114ce961beda7c1e0dd195be36a2f0d9d047c28ac62738c3a020000000453abac00ffffffff477bf2c5b5c6733881447ac1ecaff3a6f80d7016eee3513f382ad7f554015b970100000007ab6563acab5152ffffffff04e58fe1040000000009ab00526aabab526553e59790010000000002ab525a834b03000000000035fdaf0200000000086551ac65515200ab00000000", "63ac53", 1, 1285478169, "1536da582a0b6de017862445e91ba14181bd6bf953f4de2f46b040d351a747c9"], + ["4624aa9204584f06a8a325c84e3b108cafb97a387af62dc9eab9afd85ae5e2c71e593a3b690200000003636a005eb2b44eabbaeca6257c442fea00107c80e32e8715a1293cc164a42e62ce14fea146220c020000000090b9ee38106e3310037bfc519fd209bdbd21c588522a0e96df5fba4e979392bc993bfe9f01000000086363636a635353ab6f1907d218ef6f3c729d9200e23c1dbff2df58b8b1282c6717b26cf760ee4c880d23f4d100000000086a516a536a525163ffffffff01d6f162050000000000ebbab208", "525365ab0053", 1, -1515409389, "e50edcd6f503b1576673e27110f0f64a3ada27702b15840e49648d0a5aefaddf"], + ["16562fc503f1cf9113987040c408bfd4523f1512da699a2ca6ba122dc65677a4c9bf7763830000000003636552ffffffff1ec1fab5ff099d1c8e6b068156f4e39b5543286bab53c6d61e2582d1e07c96cf02000000045163656affffffffd0ef40003524d54c08cb4d13a5ee61c84fbb28cde9eca7a6d11ba3a9335d8c620100000007635153536a6300fbb84fc2012003a601000000000363ab6a00000000", "63636a006a6aab", 0, -1310262739, "f697b573b59f1a15452104c62d6768de21a877bd6a980174aa9f2e3432c0068c"], + ["531665d701f86bacbdb881c317ef60d9cd1baeffb2475e57d3b282cd9225e2a3bf9cbe0ded01000000086300ac515263acabffffffff0453a8500100000000086353acab516a6565e5e9200500000000026a52a44caa00000000000453ac000065e41b0500000000076500ac0065526ab4476f4d", "006563006aab00636a", 0, 1770013713, "29b937dfa13c6f666e7ba440f95071e27ced7f4d9c5da55dc19e78910c84850e"], + ["0f1227a20140655a3da36e413b9b5d108a866f6f147eb4940f032f5a89854eae6d7c3a91600100000009525363515153515253e37a79480161ab61020000000001ab00000000", "ab65005200", 0, -1996383599, "979782dc3f36d908d37d7e4046a38d306b4b08ddc60a5eba355fe3d6da1b29a9"], + ["063ff6eb01aff98d0d2a6db224475010edb634c2f3b46257084676adeb84165a4ff8558d7601000000066353006a5165deb3262c042d109c0000000000076363ab52ac005200b9c4050000000007516300ac510063cfffc800000000000200639e815501000000000700526a52ac6365ac7b07b8", "656552abac6500", 0, -1559847112, "674a4bcb04247f8dc98780f1792cac86b8aee41a800fc1e6f5032f6e1dccde65"], + ["3320f6730132f830c4681d0cae542188e4177cad5d526fae84565c60ceb5c0118e844f90bd030000000163ffffffff0257ec5a040000000005525251ac6538344d000000000002515200000000", "5352656a53ac516a65", 0, 788050308, "3afacaca0ef6be9d39e71d7b1b118994f99e4ea5973c9107ca687d28d8eba485"], + ["c13aa4b702eedd7cde09d0416e649a890d40e675aa9b5b6d6912686e20e9b9e10dbd40abb1000000000863ab6353515351ac11d24dc4cc22ded7cdbc13edd3f87bd4b226eda3e4408853a57bcd1becf2df2a1671fd1600000000045165516affffffff01baea300100000000076aab52ab53005300000000", "0065", 0, -1195908441, "01d3d7026551e73b6ec5d7a69a244d8e06368420a8c7214c5b8e21a6d8729fe0"], + ["d9a6f20e019dd1b5fae897fb472843903f9c3c2293a0ffb59cff2b413bae6eceab574aaf9d030000000663ab006a515102f54939032df5100100000000056a51ab65530ec28f010000000004ac5100007e874905000000000651005265ac6a00000000", "abacab63acacabab", 0, 271463190, "7fa0f18f250707ca4de75c540023264ad6753019e8e635d376acf8e7f50fc0db"], + ["157c81bf0490432b3fcb3f9a5b79e5f91f67f05efb89fa1c8740a3fe7e9bdc18d7cb6acd2203000000026351ffffffff912e48e72bbcf8a540b693cf8b028e532a950e6e63a28801f6eaad1afcc52ad00000000000b1a4b170a2b9e60e0cad88a0085137309f6807d25d5afb5c1e1d32aa10ba1cdf7df596dd0000000009525165656a51ab65ab3674fba32a76fe09b273618d5f14124465933f4190ba4e0fd09d838daafc6223b31642ac00000000086a53536551ac6565ffffffff01fe9fb6030000000008ab51656a5165636a00000000", "ab00ab6a6551", 3, -64357617, "1ddaab7f973551d71f16bd70c4c4edbf7225e64e784a6da0ee7f7a9fe4f12a0b"], + ["a2692fff03b2387f5bacd5640c86ba7df574a0ee9ed7f66f22c73cccaef3907eae791cbd230200000004536363abffffffff4d9fe7e5b375de88ba48925d9b2005447a69ea2e00495a96eafb2f144ad475b40000000008000053000052636537259bee3cedd3dcc07c8f423739690c590dc195274a7d398fa196af37f3e9b4a1413f810000000006ac63acac52abffffffff04c65fe60200000000075151536365ab657236fc020000000009005263ab00656a6a5195b8b6030000000007ac5165636aac6a7d7b66010000000002acab00000000", "51", 2, -826546646, "b020c96f62ff02a37820639e0844c42e01905dd352dbe92752ee4639fd208c81"], + ["2c5b003201b88654ac2d02ff6762446cb5a4af77586f05e65ee5d54680cea13291efcf930d0100000005ab536a006a37423d2504100367000000000004536a515335149800000000000152166aeb03000000000452510063226c8e03000000000000000000", "635251", 0, 1060344735, "175f1194a9f205ad1f6b450f639c66ca4512f5b8cd73c12cd384044abb9f76e0"], + ["f981b9e104acb93b9a7e2375080f3ea0e7a94ce54cd8fb25c57992fa8042bdf4378572859f0100000002630008604febba7e4837da77084d5d1b81965e0ea0deb6d61278b6be8627b0d9a2ecd7aeb06a0300000005ac5353536a42af3ef15ce7a2cd60482fc0d191c4236e66b4b48c9018d7dbe4db820f5925aad0e8b52a0300000008ab0063510052516301863715efc8608bf69c0343f18fb81a8b0c720898a3563eca8fe630736c0440a179129d03000000086aac6a52ac6a63ac44fec4c00408320a03000000000062c21c030000000007ac6a655263006553835f0100000000015303cd60000000000005535263536558b596e0", "00", 0, -2140385880, "49870a961263354c9baf108c6979b28261f99b374e97605baa532d9fa3848797"], + ["e7416df901269b7af14a13d9d0507709b3cd751f586ce9d5da8d16a121e1bd481f5a086e1103000000056aab005200ffffffff01aa269c040000000006acac6a6a5263ee718de6", "ab525363", 0, 1309186487, "226b1251d94157ca4111f84eb30c645cb99c544792644453fd3dcdafba077272"], + ["402a815902193073625ab13d876190d1bbb72aecb0ea733c3330f2a4c2fe6146f322d8843a0300000008656aab0000535363fffffffff9dccdec5d8509d9297d26dfcb1e789cf02236c77dc4b90ebccbf94d1b5821150300000001510bf1f96a03c5c145000000000002ac6ae11b1c0100000000055163516a5239c8a600000000000365636300000000", "63536aacab", 0, -1811425019, "13896af3106598b7ae8fe0cac194bab3ee39f0072cdb5fd63af965e5d7ccbd23"], + ["c4b702e502f1a54f235224f0e6de961d2e53b506ab45b9a40805d1dacd35148f0acf24ca5e00000000085200ac65ac53acabf34ba6099135658460de9d9b433b84a8562032723635baf21ca1db561dce1c13a06f4407000000000851ac006a63516aabffffffff02a853a603000000000163d17a67030000000005ab63006a5200000000", "ac5363515153", 1, 480734903, "5c46f7ac3d6460af0da28468fcc5b3c87f2b9093d0f837954b7c8174b4d7b6e7"], + ["9b83f78704f492b9b353a3faad8d93f688e885030c274856e4037818848b99e490afef27770200000000ffffffff36b60675a5888c0ef4d9e11744ecd90d9fe9e6d8abb4cff5666c898fdce98d9e00000000056aab656352596370fca7a7c139752971e169a1af3e67d7656fc4fc7fd3b98408e607c2f2c836c9f27c030000000653ac51ab6300a0761de7e158947f401b3595b7dc0fe7b75fa9c833d13f1af57b9206e4012de0c41b8124030000000953656a53ab53510052242e5f5601bf83b301000000000465516a6300000000", "63515200ac656365", 3, -150879312, "9cf05990421ea853782e4a2c67118e03434629e7d52ab3f1d55c37cf7d72cdc4"], + ["f492a9da04f80b679708c01224f68203d5ea2668b1f442ebba16b1aa4301d2fe5b4e2568f3010000000953005351525263ab65ffffffff93b34c3f37d4a66df255b514419105b56d7d60c24bf395415eda3d3d8aa5cd0101000000020065ffffffff9dba34dabdc4f1643b372b6b77fdf2b482b33ed425914bb4b1a61e4fad33cf390000000002ab52ffffffffbbf3dc82f397ef3ee902c5146c8a80d9a1344fa6e38b7abce0f157be7adaefae0000000009515351005365006a51ffffffff021359ba010000000000403fea0200000000095200ac6353abac635300000000", "00ac51acacac", 0, -2115078468, "a4ff27ab9542db04c2aedf27e76c998f45f57c4e3ef9ef1e3ed4abbe366420f5"], + ["2f73e0b304f154d3a00fde2fdd40e791295e28d6cb76af9c0fd8547acf3771a02e3a92ba37030000000852ac6351ab6565639aa95467b065cec61b6e7dc4d6192b5536a7c569315fb43f470078b31ed22a55dab8265f02000000080065636a6aab6a53ffffffff9e3addbff52b2aaf9fe49c67017395198a9b71f0aa668c5cb354d06c295a691a0100000000ffffffff45c2b4019abaf05c5e484df982a4a07459204d1343a6ee5badade358141f8f990300000007ac516a6aacac6308655cd601f3bc2f0000000000015200000000", "", 0, -2082054003, "126c8b2033ad9417859ba30773dc283091ff02b6fcb6a9af031b7614f554f391"], + ["5a60b9b503553f3c099f775db56af3456330f1e44e67355c4ab290d22764b9144a7b5f959003000000030052acbd63e0564decc8659aa53868be48c1bfcda0a8c9857b0db32a217bc8b46d9e7323fe9649020000000553ac6551abd0ecf806211db989bead96c09c7f3ec5f73c1411d3329d47d12f9e46678f09bac0dc383e0200000000ffffffff01494bb202000000000500516551ac00000000", "ac", 0, 1169947809, "62a36c6e8da037202fa8aeae03e533665376d5a4e0a854fc4624a75ec52e4eb1"], + ["7e98d353045569c52347ca0ff2fdba608829e744f61eb779ffdb5830aae0e6d6857ab2690e03000000075365acab656352ffffffffa890dd37818776d12da8dca53d02d243ef23b4535c67016f4c58103eed85360f030000000093dbacdc25ca65d2951e047d6102c4a7da5e37f3d5e3c8b87c29b489360725dcd117ee2003000000056a6300ac53c7e99fa1dc2b8b51733034e6555f6d6de47dbbf1026effac7db80cb2080678687380dc1e02000000075352005263516affffffff04423272040000000008ab6353ab65510051e0f53b0500000000086300516552635152f74a5f04000000000853acab0053ab52ab0e8e5f00000000000951ac5363516a6aabab00000000", "6a5163ab52", 3, 890006039, "db7c4018b659ce1398911657e996196b66ee2f1a4dfa07562872dc15f683a3db"], + ["e3649aa40405e6ffe377dbb1bbbb672a40d8424c430fa6512c6165273a2b9b6afa9949ec430200000007630052ab655153a365f62f2792fa90c784efe3f0981134d72aac0b1e1578097132c7f0406671457c332b84020000000353ab6ad780f40cf51be22bb4ff755434779c7f1def4999e4f289d2bd23d142f36b66fbe5cfbb4b01000000076a5252abac52ab1430ffdc67127c9c0fc97dcd4b578dab64f4fb9550d2b59d599773962077a563e8b6732c02000000016affffffff04cb2687000000000002ab636e320904000000000252acf70e9401000000000100dc3393050000000006ab0063536aacbc231765", "65520053", 3, -2016196547, "f64f805f0ff7f237359fa6b0e58085f3c766d1859003332223444fd29144112a"], + ["1d033569040700441686672832b531ab55db89b50dc1f9fc00fb72218b652da9dcfbc83be901000000066551ac526a632b390f9ad068e5fdee6563e88e2a8e4e09763c861072713dc069893dc6bbc9db3f00e26502000000096a5363526565525252ffffffff8a36bdd0aaf38f6707592d203e14476ca9f259021e487135c7e8324244057ed90300000000ed3fb2a3dfd4d46b5f3603fe0148653911988457bd0ed7f742b07c452f5476c228ff9f600200000007526aac00525152ffffffff04b88e48030000000000c753d602000000000853510000006553518fda2603000000000853ac52acac5263534839f1030000000006ac006aacac5300000000", "516553635300ab0052", 1, 2075958316, "c2cefaec2293134acbcf6d2a8bf2b3eb42e4ec04ee8f8bf30ff23e65680677c1"], + ["4c4be7540344050e3044f0f1d628039a334a7c1f7b4573469cfea46101d6888bb6161fe9710200000000ffffffffac85a4fdad641d8e28523f78cf5b0f4dc74e6c5d903c10b358dd13a5a1fd8a06000000000163e0ae75d05616b72467b691dc207fe2e65ea35e2eadb7e06ea442b2adb9715f212c0924f10200000000ffffffff0194ddfe02000000000265ac00000000", "00006500", 1, -479922626, "bf3b04f8e9def46f3f7d54f3babeb3a719059ddfe0351566c99c049131af396d"], + ["202c18eb012bc0a987e69e205aea63f0f0c089f96dd8f0e9fcde199f2f37892b1d4e6da90302000000055352ac6565ffffffff0257e5450100000000025300ad257203000000000000000000", "520052ac6a005265", 0, 168054797, "502967a6f999f7ee25610a443caf8653dda288e6d644a77537bcc115a8a29894"], + ["32fa0b0804e6ea101e137665a041cc2350b794e59bf42d9b09088b01cde806ec1bbea077df0200000008515153650000006506a11c55904258fa418e57b88b12724b81153260d3f4c9f080439789a391ab147aabb0fa0000000007000052ac51ab510986f2a15c0d5e05d20dc876dd2dafa435276d53da7b47c393f20900e55f163b97ce0b800000000008ab526a520065636a8087df7d4d9c985fb42308fb09dce704650719140aa6050e8955fa5d2ea46b464a333f870000000009636300636a6565006affffffff01994a0d040000000002536500000000", "516563530065", 2, -163068286, "f58637277d2bc42e18358dc55f7e87e7043f5e33f4ce1fc974e715ef0d3d1c2a"], + ["ae23424d040cd884ebfb9a815d8f17176980ab8015285e03fdde899449f4ae71e04275e9a80100000007ab006553530053ffffffff018e06db6af519dadc5280c07791c0fd33251500955e43fe4ac747a4df5c54df020000000251ac330e977c0fec6149a1768e0d312fdb53ed9953a3737d7b5d06aad4d86e9970346a4feeb5030000000951ab51ac6563ab526a67cabc431ee3d8111224d5ecdbb7d717aa8fe82ce4a63842c9bd1aa848f111910e5ae1eb0100000004ac515300bfb7e0d7048acddc030000000009636a5253636a655363a3428e040000000001525b99c6050000000004655265ab717e6e020000000000d99011eb", "ac6a6a516565", 1, -716251613, "379642424df9b62351779c1ddb723dfda61f56d8f9c49e21a1c7d1125684adb8"], + ["030f44fc01b4a9267335a95677bd190c1c12655e64df74addc53b753641259af1a54146baa020000000152e004b56c04ba11780300000000026a53f125f001000000000251acd2cc7c03000000000763536563655363c9b9e50500000000015200000000", "ac", 0, -1351818362, "64119a619eeb3d615480106d7612122dcfc3f15fe7f3d036d346c56ef3b999a6"], + ["c05f448f02817740b30652c5681a3b128322f9dc97d166bd4402d39c37c0b14506d8adb5890300000003536353ffffffffa188b430357055ba291c648f951cd2f9b28a2e76353bef391b71a889ba68d5fc02000000056565526a6affffffff02745f73010000000001ab3ec34c0400000000036aac5200000000", "516551510053", 0, -267877242, "542a0ce836c785f93d2ffa1d2448f4a4f855c7bf83e43b8342c2a00b2f223d63"], + ["163ba45703dd8c2c5a1c1f8b806afdc710a2a8fc40c0138e2d83e329e0e02a9b6c837ff6b8000000000700655151ab6a522b48b8f134eb1a7e6f5a6fa319ce9d11b36327ba427b7d65ead3b4a6a69f85cda8bbcd22030000000563656552acffffffffdbcf4955232bd11eef0cc6954f3f6279675b2956b9bcc24f08c360894027a60201000000066500006500abffffffff04d0ce9d0200000000008380650000000000015233f360040000000003006aabedcf0801000000000000000000", "000065006500ac", 0, 216965259, "55a9c6ec09e268b188f4bf8ef57b734fbbb2ddc622495010ff49af48330ebc80"], + ["07f7f5530453a12ad0c7eb8fbc3f140c7ab6818144d67d2d8752600ca5d9a9358e2dff87d4000000000663526aab526a9e599c379d455e2da36d0cde88d931a863a3e97e01e93b9edb65856f3d958dc08b92b720000000000165bbc8d66dae3b1b170a6e2457f5b161465cb8706e0e6ffc6af55deb918365f14c5f40d4890100000000a7bd77c069ee4b48638e2363fcf2a86b02bea022047bd9fcb16d2b94ad068308d19b31cb00000000066aab5300ab529672aa8f01dbd8a205000000000663536353006a02e99901", "ac006351006a63ab63", 1, 119789359, "6629a1e75c6ae8f4f9d5f734246b6a71682a5ea57246040ef0584f6b97916175"], + ["fe647f950311bf8f3a4d90afd7517df306e04a344d2b2a2fea368935faf11fa6882505890d0000000005ab5100516affffffff43c140947d9778718919c49c0535667fc6cc727f5876851cb8f7b6460710c7f60100000000ffffffffce4aa5d90d7ab93cbec2e9626a435afcf2a68dd693c15b0e1ece81a9fcbe025e0300000000ffffffff02f34806020000000002515262e54403000000000965635151ac655363636de5ce24", "6a005100ac516351", 2, 989643454, "938c6a7574977375a01f5af99e27512ceba161cce714a5c54b4b9afbe0514e7d"], + ["a1050f8604d0f9d2feefcdb5051ae0052f38e21bf39daf583fd0c3900faa3eab5d431c0bbe030000000653536a005151683d27e5c6e0da8f22125823f32d5d98477d8098ef36263b9694d61d4d85d3f2ac02b7570200000007000052005165abffffffff0cad981542bcb54a87d9400aa63e514c7c6fab7158c2b1fb37821ea755eb162a0200000000b94feb5100e5ef3bf8ed8d43356c8a8d5ac6c7e80d7ff6040f4f0aa19abbe783f4f461240200000007636500000052655686fd70042be3ad02000000000465ab636a15680b000000000004acac53511277c705000000000452635252d27a0102000000000000000000", "6a6aacab65655251", 1, -982144712, "cecb4449d837d2596ee6c4b0c2bf18e0787da4633609a3aebe02eb722d77976a"], + ["cef7316804c3e77fe67fc6207a1ea6ae6eb06b3bf1b3a4010a45ae5c7ad677bb8a4ebd16d90200000009ac536a5152ac5263005301ab8a0da2b3e0654d31a30264f9356ba1851c820a403be2948d35cafc7f9fe67a06960300000006526a63636a53ffffffffbada0d85465199fa4232c6e4222df790470c5b7afd54704595a48eedd7a4916b030000000865ab63ac006a006ab28dba4ad55e58b5375053f78b8cdf4879f723ea4068aed3dd4138766cb4d80aab0aff3d0300000003ac6a00ffffffff010f5dd6010000000006ab006aab51ab00000000", "", 1, 889284257, "d0f32a6db43378af84b063a6706d614e2d647031cf066997c48c04de3b493a94"], + ["7b3ff28004ba3c7590ed6e36f45453ebb3f16636fe716acb2418bb2963df596a50ed954d2e03000000065251515265abffffffff706ee16e32e22179400c9841013971645dabf63a3a6d2d5feb42f83aa468983e030000000653ac51ac5152ffffffffa03a16e5e5de65dfa848b9a64ee8bf8656cc1f96b06a15d35bd5f3d32629876e020000000043c1a3965448b3b46f0f0689f1368f3b2981208a368ec5c30defb35595ef9cf95ffd10e902000000036aac65253a5bbe042e907204000000000800006565656352634203b4020000000002656336b3b7010000000001ab7a063f0100000000026500a233cb76", "006551636a53ac5251", 1, -1144216171, "68c7bd717b399b1ee33a6562a916825a2fed3019cdf4920418bb72ffd7403c8c"], + ["d5c1b16f0248c60a3ddccf7ebd1b3f260360bbdf2230577d1c236891a1993725e262e1b6cb000000000363636affffffff0a32362cfe68d25b243a015fc9aa172ea9c6b087c9e231474bb01824fd6bd8bc0300000005ab52ab516affffffff0420d9a70200000000045152656a45765d0000000000055252536a5277bad100000000000252ab3f3f3803000000000463acac5200000000", "52636a52ab65", 1, 1305123842, "821d523ca037d212301ccfb1e78862947f79f92f685426971db73631535768c4"], + ["1be8ee5604a9937ebecffc832155d9ba7860d0ca451eaced58ca3688945a31d93420c27c460100000006abac5300535288b65458af2f17cbbf7c5fbcdcfb334ffd84c1510d5500dc7d25a43c36679b702e850f7c0200000003005300ffffffff7c237281cb859653eb5bb0a66dbb7aeb2ac11d99ba9ed0f12c766a8ae2a2157203000000086aabac526365acabfffffffff09d3d6639849f442a6a52ad10a5d0e4cb1f4a6b22a98a8f442f60280c9e5be80200000007ab00ab6565ab52ffffffff0398fe83030000000005526aababacbdd6ec010000000005535252ab6a82c1e6040000000001652b71c40c", "6563526353656351", 2, -853634888, "0d936cceda2f56c7bb87d90a7b508f6208577014ff280910a710580357df25f3"], + ["9e0f99c504fbca858c209c6d9371ddd78985be1ab52845db0720af9ae5e2664d352f5037d4010000000552ac53636affffffff0e0ce866bc3f5b0a49748f597c18fa47a2483b8a94cef1d7295d9a5d36d31ae7030000000663515263ac635bb5d1698325164cdd3f7f3f7831635a3588f26d47cc30bf0fefd56cd87dc4e84f162ab702000000036a6365ffffffff85c2b1a61de4bcbd1d5332d5f59f338dd5e8accbc466fd860f96eef1f54c28ec030000000165ffffffff04f5cabd010000000007000052ac526563c18f1502000000000465510051dc9157050000000008655363ac525253ac506bb600000000000865656a53ab63006a00000000", "006a6a0052", 0, 1186324483, "2f9b7348600336512686e7271c53015d1cb096ab1a5e0bce49acd35bceb42bc8"], + ["11ce51f90164b4b54b9278f0337d95c50d16f6828fcb641df9c7a041a2b274aa70b1250f2b0000000008ab6a6a65006551524c9fe7f604af44be050000000005525365006521f79a0300000000015306bb4e04000000000265ac99611a05000000000765acab656500006dc866d0", "", 0, -1710478832, "1ead10bb76fbaf192b50c7912c10f3ee360f87b246855a1311b5e2251b41931e"], + ["86bc233e02ba3c647e356558e7252481a7769491fb46e883dd547a4ce9898fc9a1ca1b77790000000006ab5351abab51f0c1d09c37696d5c7c257788f5dff5583f4700687bcb7d4acfb48521dc953659e325fa390300000003acac5280f29523027225af03000000000963abac0065ab65acab7e59d90400000000016549dac846", "53006aac52acac", 0, 711159811, "2772b75a34fc5495fa22fc3a42620f56be84dccef1ca480f1a261c924e3925fa"], + ["beac155d03a853bf18cd5c490bb2a245b3b2a501a3ce5967945b0bf388fec2ba9f04c03d68030000000012fe96283aec4d3aafed8f888b0f1534bd903f9cd1af86a7e64006a2fa0d2d30711af770010000000163ffffffffd963a19d19a292104b9021c535d3e302925543fb3b5ed39fb2124ee23a9db00302000000056500ac63acffffffff01ad67f503000000000300ac5189f78db2", "53536a636500", 2, 748992799, "8cb75328857670f75ccfa115f767b8d69ba8cf022f3acd958d5a0b538cb62415"], + ["81dab34a039c9e225ba8ef421ec8e0e9d46b5172e892058a9ade579fe0eb239f7d9c97d45b0300000009ac65655351ab526363ffffffff10c0faaf7f597fc8b00bbc67c3fd4c6b70ca6b22718d15946bf6b032e62dae570000000005536a00ab6a02cddec3acf985bbe62c96fccf17012a87026ed63fc6756fa39e286eb4c2dd79b59d37400300000002516affffffff04f18b8d03000000000753abab5152636564411c02000000000400ab6300e965750300000000001bd2cf02000000000565ab526aab00000000", "006551ab", 0, -1488174549, "ec2cf03e2aa877921ec1fbce7ce6ef17442ace100df4066da974dfe3bda3824c"], + ["489ebbf10478e260ba88c0168bd7509a651b36aaee983e400c7063da39c93bf28100011f280100000004abab63ab2fc856f05f59b257a4445253e0d91b6dffe32302d520ac8e7f6f2467f7f6b4b65f2f59e903000000096353abacab6351656affffffff0122d9480db6c45a2c6fd68b7bc57246edffbf6330c39ccd36aa3aa45ec108fc030000000265ab9a7e78a69aadd6b030b12602dff0739bbc346b466c7c0129b34f50ae1f61e634e11e9f3d0000000006516a53525100ffffffff011271070000000000086563ab6353536352c4dd0e2c", "", 0, -293358568, "674370928240355e257a64e7fd798cf0b9f2d1da8bff77f6a92d078f36f73253"], + ["6911195d04f449e8eade3bc49fd09b6fb4b7b7ec86529918b8593a9f6c34c2f2d301ec378b000000000263ab49162266af054643505b572c24ff6f8e4c920e601b23b3c42095881857d00caf56b28acd030000000565525200ac3ac4d24cb59ee8cfec0950312dcdcc14d1b360ab343e834004a5628d629642422f3c5acc02000000035100accf99b663e3c74787aba1272129a34130668a877cc6516bfb7574af9fa6d07f9b4197303400000000085351ab5152635252ffffffff042b3c95000000000000ff92330200000000046a5252ab884a2402000000000853530065520063000d78be03000000000953abab52ab53ac65aba72cb34b", "6a", 2, -637739469, "027dda1d00f9e665bcddacac5c5d30f863499188ea766c085a01f476d4b138ca"], + ["746347cf03faa548f4c0b9d2bd96504d2e780292730f690bf0475b188493fb67ca58dcca4f0000000002005336e3521bfb94c254058e852a32fc4cf50d99f9cc7215f7c632b251922104f638aa0b9d080100000008656aac5351635251ffffffff4da22a678bb5bb3ad1a29f97f6f7e5b5de11bb80bcf2f7bb96b67b9f1ac44d09030000000365ababffffffff036f02b30000000000076353ab6aac63ac50b72a050000000002acaba8abf804000000000663006a6a6353797eb999", "acac5100", 1, -1484493812, "164c32a263f357e385bd744619b91c3f9e3ce6c256d6a827d6defcbdff38fa75"], + ["e17149010239dd33f847bf1f57896db60e955117d8cf013e7553fae6baa9acd3d0f1412ad90200000006516500516500cb7b32a8a67d58dddfb6ceb5897e75ef1c1ff812d8cd73875856487826dec4a4e2d2422a0100000004ac525365196dbb69039229270400000000070000535351636a8b7596020000000006ab51ac52655131e99d040000000003516551ee437f5c", "ac656a53", 1, 1102662537, "749cea8becb08dcba94fd78d8b5ddaf3430df1e4191a36f90b7bac447ba432ac"], + ["144971940223597a2d1dec49c7d4ec557e4f4bd207428618bafa3c96c411752d494249e1fb0100000004526a5151ffffffff340a545b1080d4f7e2225ff1c9831f283a7d4ca4d3d0a29d12e07d86d6826f7f0200000003006553ffffffff03c36965000000000000dfa9af00000000000451636aac7f7d140300000000016300000000", "", 1, -108117843, "00f78debbf3790516dda4062cb0f8a175af276626253faab3e7ede69a426e646"], + ["b11b6752044e650b9c4744fb9c930819227d2ac4040d8c91a133080e090b042a142e93906e0000000003650053ffffffff6b9ce7e29550d3c1676b702e5e1537567354b002c8b7bb3d3535e63ad03b50ea01000000055100516300fffffffffcf7b252fea3ad5a108af3640a9bc2cd724a7a3ce22a760fba95496e88e2f2e801000000036a00ac7c58df5efba193d33d9549547f6ca839f93e14fa0e111f780c28c60cc938f785b363941b000000000863ab51516552ac5265e51fcd0308e9830400000000036a00abab72190300000000016a63d0710000000000050051ab6a6300000000", "53005165ac51ab65", 0, 229563932, "e562579d1a2b10d1c5e45c06513456002a6bec157d7eb42511d30b118103c052"], + ["2aee6b9a02172a8288e02fac654520c9dd9ab93cf514d73163701f4788b4caeeb9297d2e250300000004ab6363008fb36695528d7482710ea2926412f877a3b20acae31e9d3091406bfa6b62ebf9d9d2a6470100000009535165536a63520065ffffffff03f7b560050000000003acab6a9a8338050000000000206ce90000000000056552516a5100000000", "5252", 1, -1102319963, "fa4676c374ae3a417124b4c970d1ed3319dc3ac91fb36efca1aa9ed981a8aa1b"], + ["9554595203ad5d687f34474685425c1919e3d2cd05cf2dac89d5f33cd3963e5bb43f8706480100000000ffffffff9de2539c2fe3000d59afbd376cb46cefa8bd01dbc43938ff6089b63d68acdc2b02000000096553655251536a6500fffffffff9695e4016cd4dfeb5f7dadf00968e6a409ef048f81922cec231efed4ac78f5d010000000763abab6a5365006caaf0070162cc640200000000045163ab5100000000", "", 0, -1105256289, "e8e10ed162b1a43bfd23bd06b74a6c2f138b8dc1ab094ffb2fa11d5b22869bee"], + ["04f51f2a0484cba53d63de1cb0efdcb222999cdf2dd9d19b3542a896ca96e23a643dfc45f00200000007acac53510063002b091fd0bfc0cfb386edf7b9e694f1927d7a3cf4e1d2ce937c1e01610313729ef6419ae7030000000165a3372a913c59b8b3da458335dc1714805c0db98992fd0d93f16a7f28c55dc747fe66a5b503000000095351ab65ab52536351ffffffff5650b318b3e236802a4e41ed9bc0a19c32b7aa3f9b2cda1178f84499963a0cde000000000165ffffffff0383954f04000000000553ac536363a8fc90030000000000a2e315000000000005acab00ab5100000000", "0053", 2, -1424653648, "a5bc0356f56b2b41a2314ec05bee7b91ef57f1074bcd2efc4da442222269d1a3"], + ["5e4fab42024a27f0544fe11abc781f46596f75086730be9d16ce948b04cc36f86db7ad50fd01000000026a00613330f4916285b5305cc2d3de6f0293946aa6362fc087727e5203e558c676b314ef8dd401000000001af590d202ba496f040000000001009e3c9604000000000351ac51943d64d3", "51acabab5100ab52", 1, -129301207, "556c3f90aa81f9b4df5b92a23399fe6432cf8fecf7bba66fd8fdb0246440036c"], + ["a115284704b88b45a5f060af429a3a8eab10b26b7c15ed421258f5320fa22f4882817d6c2b0300000003005300ffffffff4162f4d738e973e5d26991452769b2e1be4b2b5b7e8cbeab79b9cf9df2882c040000000006636aac63ac5194abc8aa22f8ddc8a7ab102a58e39671683d1891799d19bd1308d24ea6d365e571172f1e030000000700515352515153ffffffff4da7ad75ce6d8541acbb0226e9818a1784e9c97c54b7d1ff82f791df1c6578f60000000000ffffffff01b1f265040000000009ab0051ac656a516a5300000000", "51abab6352535265", 0, -1269106800, "0ef7b6e87c782fa33fe109aab157a2d9cddc4472864f629510a1c92fa1fe7fc1"], + ["f3f771ae02939752bfe309d6c652c0d271b7cab14107e98032f269d92b2a8c8853ab057da8010000000563ab6a6365670c305c38f458e30a7c0ab45ee9abd9a8dc03bae1860f965ffced879cb2e5d0bb156821020000000153ffffffff025dc619050000000002ac51ec0d250100000000076a5200636a6363333aecd8", "650053ac515100ab", 1, 1812404608, "a7aa34bf8a5644f03c6dd8801f9b15ba2e07e07256dbf1e02dad59f0d3e17ea9"], + ["fd3e267203ae7d6d3975e738ca84f12540229bb237dd228d5f688e9d5ba53fce4302b0334d01000000026353ffffffff602a3ab75af7aa951d93093e345ef0037a2863f3f580a9b1a575fffe68e677450300000000239e476d1e8f81e8b6313880d8a49b27c1b00af467f29756e76f675f084a5676539636ab030000000765ab6351acac52d9217747044d773204000000000752ac51526353acc33e45050000000005516500005115d889040000000004ab5163510cbbbd0200000000016500000000", "65ac526aac6a53ab52", 2, -886179452, "ca02ad725af8a182e3475205bcae3c8b50ecf6f2186e8de73234c2f1e4efd0e8"], + ["f380ae23033646af5dfc186f6599098015139e961919aea28502ea2d69474413d94a555ea2000000000853635265abacac5314da394b99b07733341ddba9e86022637be3b76492992fb0f58f23c915098979250a96620300000003ab6300ffffffff4bb6d1c0a0d84eac7f770d3ad0fdc5369ae42a21bbe4c06e0b5060d5990776220300000000ffffffff0486fd70020000000007ac6500635252acf3fd72010000000005656a6a6551212de90500000000096365006a63635153000fa33100000000000600535151656300000000", "ab52", 2, -740890216, "a50666837ad4b9119c9feb34319a0c105a9b8aee8a87713045f95f5701d1ddcb"], + ["5c45d09801bb4d8e7679d857b86b97697472d514f8b76d862460e7421e8617b15a2df217c6010000000863acacab6565006affffffff01156dbc03000000000952ac63516551ac6aac00000000", "6aabac", 0, 1310125827, "9aaf5ce087b794f231346b6246cb64d823b007c9c4f9d4d15458e339e6115ba7"], + ["4ecc6bde030ca0f83c0ed3d4b777f94c0c88708c6c933fe1df6874f296d425cac95355c23d0000000006ac6a51536a52f286a0969d6170e20f2a8000193807f5bc556770e9d82341ef8e17b0035eace89c76edd50200000007ac65525100656affffffff5bade6e462fac1927f078d69d3a981f5b4c1e59311a38efcb9a910aa436afaa80000000007ac6a006352ab52ffffffff0331e58902000000000763ac53636352abb8b3ca000000000001637a1d26040000000009535263ac6a5352ab655ae34a39", "6a65ab", 2, 2142728453, "48fd7c434664c386c5d10e17c3e7a949cb7a6efb5f393a384fdc6bbe4cd38e3d"], + ["a59484b501eb50114be0fc79e72ab9bc9f4a5f7acdf274a56d6b68684eb68cf8b07ec5d1c2000000000765abab00ab00639e09aa940141e3530200000000046500ac6500000000", "00516565ab", 0, -1561622469, "e3dd1c11ab3503cea886251d5d236eea8dd180e64eb012fb825ab802d540c318"], + ["53dc1a88046531c7b57a35f4d9adf101d068bf8d63fbbedaf4741dba8bc5e92c8725def571030000000453655251fcdf116a226b3ec240739c4c7493800e4edfe67275234e371a227721eac43d3d9ecaf1b50300000003ac0052ffffffff2c9279ffeea4718d167e9499bd067600715c14484e373ef93ae4a31d2f5671ab0000000009516553ac636a6a65001977752eeba95a8f16b88c571a459c2f2a204e23d48cc7090e4f4cc35846ca7fc0a455ce00000000055165ac0063188143f80205972902000000000765ac63ac516353c7b6a50000000000036a510000000000", "655351536a", 0, 103806724, "41837a0d6f3c27a44421056e316ecfee0adc1c18a9317ab1a66b83c5434fd913"], + ["53f8959f01ddb36afdcd20167edcbb75a63d18654fdcf10bc0004c761ab450fe236d79cb2702000000065151650063653435003a033a5e34050000000009ac52516a630000516ab86db3030000000002006344ac090500000000046363ab00f3644537", "5263abab63ac656353", 0, -218513617, "2068a331c601165b31b05b5fc984b76c5ea4cbe7ea0324fbe46738803702a905"], + ["5a06cb4602dcfc85f49b8d14513f33c48f67146f2ee44959bbca092788e6823b2719f3160b0200000001ab3c013f2518035b9ea635f9a1c74ec1a3fb7496a160f46aae2e09bfc5cd5111a0f20969e003000000015158c89ab7049f20d6010000000008ac6a52abac53515349765e00000000000300ab638292630100000000045351ab0086da09010000000006656a6365525300000000", "526a63", 1, 1502936586, "bdfaff8a4e775379c5dc26e024968efa805f923de53fa8272dd53ec582afa0c5"], + ["ca9d84fa0129011e1bf27d7cb71819650b59fb292b053d625c6f02b0339249b498ff7fd4b601000000025352ffffffff032173a0040000000008525253abab5152639473bb030000000009005153526a53535151d085bd0000000000086a5365ab5165655300000000", "005152ac51", 0, 580353445, "c629d93b02037f40aa110e46d903edb34107f64806aa0c418d435926feef68b8"], + ["e3cdbfb4014d90ae6a4401e85f7ac717adc2c035858bf6ff48979dd399d155bce1f150daea0300000002ac51a67a0d39017f6c71040000000005535200535200000000", "", 0, -1899950975, "bc1571d8b20eedc2a481aac167fa73d316959e16e4c32e2e867596d0c3d6ca6d"], + ["b2b6b9ab0283d9d73eeae3d847f41439cd88279c166aa805e44f8243adeb3b09e584efb1df00000000026300ffffffff7dfe653bd67ca094f8dab51007c6adaced09de2af745e175b9714ca1f5c68d050000000003ac6500aa8e596903fd3f3204000000000553ac6a6a533a2e210500000000075253acabab526392d0ee020000000008520065635200ab5200000000", "65acacac65005365", 0, 28298553, "39c2aaa2496212b3ab120ab7d7f37c5e852bfe38d20f5226413a2268663eeae8"], + ["f30c5c3d01a6edb9e10fafaf7e85db14e7fec558b9dca4a80b05d7c3a2944d282c5018f4680200000003005263ffffffff04aac3530300000000026551bc2419010000000009005163acab6a5100658e7085050000000000c5e4ec050000000007656a6a635365ab2d8e8882", "abac53ab005251ac52", 0, -490287610, "5d116375b43d980753b8b68279b0dfd17bfd5a91f8a3797e86926de614a4c529"], + ["4314339e01de40faabcb1b970245a7f19eedbc17c507dac86cf986c2973715035cf95736ae0200000007abababababab65bde67b900151510b04000000000853ac00655200535300000000", "52", 0, 399070095, "47585dc25469d04ff3a60939d0a03779e3e81a411bf0ca18b91bb925ebd30718"], + ["2d4cf4e9031b3e175b2ff18cd933151379d9cfac4713d8bd0e63b70bd4a92277aa7af901ab000000000565515353abffffffff557666c7f3be9cdecdad44c3df206eb63a2da4ed1f159d21193882a9f0340081020000000963ab53ab5252ac63abffffffff8a8c897bdb87e93886aad5ded9d82a13101d5476554386373646ca5e23612e450300000009006a526552abab6a635ac03fc00198bb02040000000009525100526a6563636a1d052834", "ab52ac00acac6a", 0, -1469882480, "09ed6563a454814ab7e3b4c28d56d8751162b77df1825b37ba66c6147750b2a3"], + ["f063171b03e1830fdc1d685a30a377537363ccafdc68b42bf2e3acb908dac61ee24b37595c020000000765ac5100ab6aacf447bc8e037b89d6cadd62d960cc442d5ced901d188867b5122b42a862929ce45e7b628d010000000253aba009a1ba42b00f1490b0b857052820976c675f335491cda838fb7934d5eea0257684a2a202000000001e83cf2401a7f777030000000008ab6553526a53526a00000000", "", 2, 1984790332, "c19caada8e71535e29a86fa29cfd9b74a0c7412003fc722a121005e461e01636"], + ["cf7bdc250249e22cbe23baf6b648328d31773ea0e771b3b76a48b4748d7fbd390e88a004d30000000003ac536a4ab8cce0e097136c90b2037f231b7fde2063017facd40ed4e5896da7ad00e9c71dd70ae600000000096a0063516352525365ffffffff01b71e3e00000000000300536a00000000", "", 1, 546970113, "6a815ba155270af102322c882f26d22da11c5330a751f520807936b320b9af5d"], + ["ac7a125a0269d35f5dbdab9948c48674616e7507413cd10e1acebeaf85b369cd8c88301b7c030000000963656aac6a530053abffffffffed94c39a582e1a46ce4c6bffda2ccdb16cda485f3a0d94b06206066da12aecfe010000000752abab63536363ef71dcfb02ee07fa0400000000016a6908c802000000000751656a6551abac688c2c2d", "6a6351526551", 0, 858400684, "552ff97d7924f51cda6d1b94be53483153ef725cc0a3a107adbef220c753f9a6"], + ["3a1f454a03a4591e46cf1f7605a3a130b631bf4dfd81bd2443dc4fac1e0a224e74112884fe0000000005516aac6a53a87e78b55548601ffc941f91d75eab263aa79cd498c88c37fdf275a64feff89fc1710efe03000000016a39d7ef6f2a52c00378b4f8f8301853b61c54792c0f1c4e2cd18a08cb97a7668caa008d970200000002656affffffff017642b20100000000096a63535253abac6a6528271998", "51", 2, 1459585336, "44e7897b4865d4c5030e71af907075656b409dea4611184b0694f893912bd61a"], + ["f59366cc0114c2a18e6bd1347ed9470f2522284e9e835dd5c5f7ef243639ebea95d9b232b6020000000153474b62eb045c00170500000000096352ab516352ab5200038a520400000000086aab5253656a63005b968904000000000963536353ac0053635387106002000000000000000000", "ab52526300ab51", 0, 1834116153, "cdf51f6e3a9dc2be5a59ea4c00f5aac1e1426a5202c325e6cf2567d07d8d8de4"], + ["6269e0fa0173e76e89657ca495913f1b86af5b8f1c1586bcd6c960aede9bc759718dfd5044000000000352ac530e2c7bd90219849b000000000007ab00ab6a53006319f281000000000007ab00515165ac5200000000", "6a", 0, -2039568364, "e41202077994b4d05eaa8ca9478ad68b0cda7dc033c46bab8fb7861f64d37e1b"], + ["eb2bc00604815b9ced1c604960d54beea4a3a74b5c0035d4a8b6bfec5d0c9108f143c0e99a0000000000ffffffff22645b6e8da5f11d90e5130fd0a0df8cf79829b2647957471d881c2372c527d8010000000263acffffffff1179dbaf17404109f706ae27ad7ba61e860346f63f0c81cb235d2b05d14f2c1003000000025300264cb23aaffdc4d6fa8ec0bb94eff3a2e50a83418a8e9473a16aaa4ef8b855625ed77ef40100000003ac51acf8414ad404dd328901000000000652526500006ab6261c000000000002526a72a4c9020000000006ac526500656586d2e7000000000006656aac00ac5279cd8908", "51", 1, -399279443, "1c34c0199f19a6b3c4477795953a24e4ed2e6f8914daa4c670101a09a0116508"], + ["dc9fe6a8038b84209bbdae5d848e8c040433237f415437592907aa798bf30d9dbbddf0ff85010000000153ffffffff23269a7ea29fcf788db483b8d4c4b35669e582608644259e950ce152b0fa6e050000000003acababffffffff65de94857897ae9ea3aa0b938ba6e5adf374d48469922d2b36dbb83d3b8c8261010000000452ac5200ffffffff02856e9b0300000000026a51980c8e02000000000365ab63d2648db4", "00ab0051ac526565", 2, 1562581941, "5cef9d8e18a2d5a70448f17b465d411a19dab78f0ddf1672ffd518b188f52433"], + ["eba8b0de04ac276293c272d0d3636e81400b1aaa60db5f11561480592f99e6f6fa13ad387002000000070053acab536563bebb23d66fd17d98271b182019864a90e60a54f5a615e40b643a54f8408fa8512cfac927030000000963ac6a6aabac65ababffffffff890a72192bc01255058314f376bab1dc72b5fea104c154a15d6faee75dfa5dba020000000100592b3559b0085387ac7575c05b29b1f35d9a2c26a0c27903cc0f43e7e6e37d5a60d8305a030000000252abffffffff0126518f05000000000000000000", "005300635252635351", 1, 664344756, "26dc2cba4bd5334e5c0b3a520b44cc1640c6b923d10e576062f1197171724097"], + ["91bd040802c92f6fe97411b159df2cd60fb9571764b001f31657f2d616964637605875c2a901000000055263006a65ffffffff3651df372645f50cf4e32fdf6e61c766e912e16335db2b40c5d52fe89eefe7cd00000000040065ab65ffffffff03ca8625030000000009ab51ac63530052ab52c6bf14020000000006ab00ab52005167d270000000000007ab53525351636a00000000", "5151ab63005252ac", 1, 1983087664, "3e5aa0200248d8d86ede3b315ca1b857018b89184a4bd023bd88ab12e499f6e1"], + ["185cda1a01ecf7a8a8c28466725b60431545fc7a3367ab68e34d486e8ea85ee3128e0d8384000000000465ac63abec88b7bb031c56eb04000000000965636a51005252006a7c78d5040000000007acac63abac51ac3024a40500000000086300526a51abac51464c0e8c", "0065535265515352", 0, 1594558853, "970faa50aac5d5aac37275012b4b5fbd82e11c5c9fc8c12386323bc06fb24ca6"], + ["a9531f07034091668b65fea8b1a79700d586ac9e2f42ca0455a26abe41f9e1805d009a0f5702000000096365516365ac5263ab3619bac643a9e28ee47855118cf80c3a74531cdf198835d206d0fe41804e325a4f9f105e03000000016a58e3ab0d46375d98994daf0fa7c600d2bb4669e726fca0e3a3f21ea0d9e777396740328f0100000008636a5363ab526a538d3ea7700304cb66030000000007515163ab52ab510184030500000000085353636565ac0051d9cff402000000000751ab52ab5352abf0e36254", "ab5353ac5365acab", 2, 1633101834, "04c9ef72f33668ca449c0415becf62cc0b8e0c75f9c8813852d42a58acf107c8"], + ["6b5ecc7903fe0ba37ea551df92a59e12bad0a3065846ba69179a8f4a741a2b4fcf679aac810200000004535263529a3d343293b99ab425e7ef8529549d84f480bcd92472bab972ea380a302128ae14dfcd0200000000025163ffffffff24636e4545cab9bf87009119b7fc3ec4d5ee9e206b90f35d1df8a563b6cd097a010000000852abac53005153abc64467860406e832020000000009526300006a53ac6352ac1395010000000002ac53b117f300000000000863655351acab00651edf02030000000008ab51ac6353535252628ef71d", "ab63ab6a52ac526563", 2, -1559697626, "8f07ece7d65e509f1e0780584ef8d271c1c61a13b10335d5faafc7afc8b5b8ec"], + ["92c9fb780138abc472e589d5b59489303f234acc838ca66ffcdf0164517a8679bb622a4267020000000153468e373d04de03fa020000000009ac006a5265ab5163006af649050000000007515153006a00658ceb59030000000001ac36afa0020000000009ab53006351ab51000000000000", "6a", 0, 2059357502, "e2358dfb51831ee81d7b0bc602a65287d6cd2dbfacf55106e2bf597e22a4b573"], + ["6f62138301436f33a00b84a26a0457ccbfc0f82403288b9cbae39986b34357cb2ff9b889b302000000045253655335a7ff6701bac9960400000000086552ab656352635200000000", "6aac51", 0, 1444414211, "502a2435fd02898d2ff3ab08a3c19078414b32ec9b73d64a944834efc9dae10c"], + ["9981143a040a88c2484ac3abe053849e72d04862120f424f373753161997dd40505dcb4783030000000700536365536565a2e10da3f4b1c1ad049d97b33f0ae0ea48c5d7c30cc8810e144ad93be97789706a5ead180100000003636a00ffffffffbdcbac84c4bcc87f03d0ad83fbe13b369d7e42ddb3aecf40870a37e814ad8bb5010000000963536a5100636a53abffffffff883609905a80e34202101544f69b58a0b4576fb7391e12a769f890eef90ffb72020000000651656352526affffffff04243660000000000004ab5352534a9ce001000000000863656363ab6a53652df19d030000000003ac65acedc51700000000000000000000", "ac6300acac", 2, 293672324, "d81332b32ba5e0ea45ba01009f22da840a821a245ff0bd9c4f4203189b9fc432"], + ["a2bb630b01989bc5d643f2da4fb9b55c0cdf846ba06d1dbe372893024dbbe5b9b8a1900af802000000055265ac63aca7a68d2f04916c74010000000003abac007077f0040000000001007d4127010000000005ac516aac000f31e8030000000000571079c9", "65ab0051ac", 0, -1103627757, "58b0a5c8cd6988cbec64ee2d57df895111d794e470eadaf580ede8af3c2f417e"], + ["49f7d0b6037bba276e910ad3cd74966c7b3bc197ffbcfefd6108d6587006947e97789835ea0300000008526a52006a650053ffffffff8d7b6c07cd10f4c4010eac7946f61aff7fb5f3920bdf3467e939e58a1d4100ab03000000076aac63ac535351ffffffff8f48c3ba2d52ad67fbcdc90d8778f3c8a3894e3c35b9730562d7176b81af23c80100000003ab5265ffffffff0301e3ef0300000000046a525353e899ac0500000000075153ab6a65abac259bea0400000000007b739972", "53516aacac6aac", 1, 955403557, "5d366a7f4346ae18aeb7c9fc4dab5af71173184aa20ed22fcb4ea8511ad25449"], + ["58a4fed801fbd8d92db9dfcb2e26b6ff10b120204243fee954d7dcb3b4b9b53380e7bb8fb60100000003006351ffffffff02a0795b050000000006536351ac6aac2718d00200000000075151acabac515354d21ba1", "005363515351", 0, -1322430665, "bbee941bbad950424bf40e3623457db47f60ed29deaa43c99dec702317cb3326"], + ["32765a0b02e455793d9ce530e9f6a44bcbc612e893a875b5da61d822dc56d8245166c398b403000000085353abac6300006a6bdee2a78d0d0b6a5ea666eed70b9bfea99d1d612ba3878f615c4da10d4a521cba27155002000000035363abffffffff043cd42401000000000551656a53653685320100000000030000511881bc0500000000065165abab636a20169f010000000007acab656aac63acdb0706a8", "65ac53ab53", 0, 1936499112, "bd934420a650f584aa5769c9a944f811e9c36655dbdf41f25d93d6a5236efe02"], + ["17fad0d303da0d764fedf9f2887a91ea625331b28704940f41e39adf3903d8e75683ef6d46020000000151ffffffffff376eea4e880bcf0f03d33999104aafed2b3daf4907950bb06496af6b51720a020000000900636a63525253525196521684f3b08497bad2c660b00b43a6a517edc58217876eb5e478aa3b5fda0f29ee1bea00000000046aacab6affffffff03dde8e2050000000007ac5365ac51516a14772e000000000005630000abacbbb360010000000006ab5251ab656a50f180f0", "0053", 0, -1043701315, "9a3f606e005ba1585243303c9eb2ae1a81fae4af26827ef8b1ea5b5a294749f1"], + ["236c32850300045e292c84ede2b9ab5733ba08315a2bb09ab234c4b4e8894808edbdac0d3b020000000653635363abacffffffffd3f696bb31fdd18a72f3fc2bb9ae54b416a253fc37c1a0f0180b52d35bad49440100000004650053abffffffffa85c75a2406d82a93b12e555b66641c1896a4e83ae41ef1038218311e38ace060200000006abab006a51ac104b5e6701e2842c04000000000800630051ac0000ab00000000", "ab63ac6a516a", 1, -1709887588, "49f3dc19a90e0c88d0f485e98c0960619aa354e127bdaba1392ffa6a84002657"], + ["b78d5fd601345f3100af494cdf447e7d4076179f940035b0ebe8962587d4d0c9c6c9fc34ee0300000003516a6affffffff03dc5c890100000000085353ac53ac6a52534ac941040000000007ac63656a51ab51d4266b0100000000036aacac70731f2d", "005351ab0053", 0, -1789071329, "8013411073b441be2d188125e369014c38f6ec6560e368a996b0c4ba2773fe39"], + ["5a2257df03554550b774e677f348939b37f8e765a212e566ce6b60b4ea8fed4c9504b7f7d1000000000653655265ab5258b67bb931df15b041177cf9599b0604160b79e30f3d7a594e7826bae2c29700f6d8f8f40300000005515300ac6a159cf8808a41f504eb5c2e0e8a9279f3801a5b5d7bc6a70515fbf1c5edc875bb4c9ffac500000000050063510052ffffffff0422a90105000000000965006a650000516a006417d2020000000006526363ab00524d969d0100000000035153acc4f077040000000005ac5200636500000000", "6a52", 1, -1482463464, "37b794b05d0687c9b93d5917ab068f6b2f0e38406ff04e7154d104fc1fb14cdc"], + ["e0032ad601269154b3fa72d3888a3151da0aed32fb2e1a15b3ae7bee57c3ddcffff76a1321010000000100110d93ae03f5bd080100000000075263516a6551002871e60100000000046a005252eaa753040000000004ab6aab526e325c71", "630052", 0, -1857873018, "ea117348e94de86381bb8ad1c7f93b8c623f0272104341701bb54e6cb433596c"], + ["014b2a5304d46764817aca180dca50f5ab25f2e0d5749f21bb74a2f8bf6b8b7b3fa8189cb7030000000965ac5165ab6a51ac6360ecd91e8abc7e700a4c36c1a708a494c94bb20cbe695c408543146566ab22be43beae9103000000045163ab00ffffffffffa48066012829629a9ec06ccd4905a05df0e2b745b966f6a269c9c8e13451fc00000000026565ffffffffc40ccadc21e65fe8a4b1e072f4994738ccaf4881ae6fede2a2844d7da4d199ab02000000065152ab536aabffffffff01b6e054030000000004515352ab3e063432", "", 0, 1056459916, "a7aff48f3b8aeb7a4bfe2e6017c80a84168487a69b69e46681e0d0d8e63a84b6"], + ["c4ef04c103c5dde65410fced19bf6a569549ecf01ceb0db4867db11f2a3a3eef0320c9e8e001000000085100536a53516aabffffffff2a0354fa5bd96f1e28835ffe30f52e19bd7d5150c687d255021a6bec03cf4cfd03000000056a006300514900c5b01d3d4ae1b97370ff1155b9dd0510e198d266c356d6168109c54c11b4c283dca00300000002ababffffffff02e19e3003000000000451655351fa5c0003000000000163ef1fc64b", "51636a51ab630065", 1, -1754709241, "475e3bcea40262ae745044086f8092165cc4e846c12467da83010400fb7151f8"], + ["29083fe00398bd2bb76ceb178f22c51b49b5c029336a51357442ed1bac35b67e1ae6fdf13100000000066a6500acab51ffffffffe4ca45c9dc84fd2c9c47c7281575c2ba4bf33b0b45c7eca8a2a483f9e3ebe4b3010000000200abffffffffdf47ad2b8c263fafb1e3908158b18146357c3a6e0832f718cd464518a219d18303000000096352ac656351ac0052daddfb3b0231c36f00000000000400526a5275c7e0020000000001ab00000000", "acab536aac52", 2, 300802322, "2f0d9e8cfbd9406b65d26804e9a5638e55638602423eb96fc456ccc4788a2699"], + ["1201ab5d04f89f07c0077abd009762e59db4bb0d86048383ba9e1dad2c9c2ad96ef660e6d00200000007ab6a65ac5200652466fa5143ab13d55886b6cdc3d0f226f47ec1c3020c1c6e32602cd3428aceab544ef43e00000000086a6a6a526a6a5263ffffffffd5be0b0be13ab75001243749c839d779716f46687e2e9978bd6c9e2fe457ee48020000000365abab1e1bac0f72005cf638f71a3df2e3bbc0fa35bf00f32d9c7dc9c39a5e8909f7d53170c8ae0200000008ab6a51516363516affffffff02f0a6210500000000036300ac867356010000000009acab65ac6353536a659356d367", "ac53535252", 0, 917543338, "418acc156c2bc76a5d7baa58db29f1b4cf6c266c9222ed167ef5b4d47f0e0f41"], + ["344fa11e01c19c4dd232c77742f0dd0aeb3695f18f76da627628741d0ee362b0ea1fb3a2180200000007635151005100529bab25af01937c1f0500000000055153ab53656e7630af", "6351005163ac51", 0, -629732189, "3aa5bf47ee00a6b6000570570565e0bb5fa3c17755ccee6688202829dda52776"], + ["b2fda1950191358a2b855f5626a0ebc830ab625bea7480f09f9cd3b388102e35c0f303124c030000000565ac65ab53ffffffff03f9c5ec04000000000765ab51516551650e2b9f0500000000045365525284e8f6040000000001ac00000000", "ac51655253", 0, 1433027632, "d2fa7e13c34cecda5105156bd2424c9b84ee0a07162642b0706f83243ff811a8"], + ["a4a6bbd201aa5d882957ac94f2c74d4747ae32d69fdc765add4acc2b68abd1bdb8ee333d6e0300000008516a6552515152abffffffff02c353cb040000000007ac6351ab51536588bd320500000000066552525253ac00000000", "", 0, 1702060459, "499da7d74032388f820645191ac3c8d20f9dba8e8ded7fa3a5401ea2942392a1"], + ["584e8d6c035a6b2f9dac2791b980a485994bf38e876d9dda9b77ad156eee02fa39e19224a60300000003ab636529db326cc8686a339b79ab6b6e82794a18e0aabc19d9ad13f31dee9d7aad8eff38288588020000000452530052ffffffff09a41f07755c16cea1c7e193c765807d18cadddca6ec1c2ed7f5dcdca99e90e80000000001acffffffff01cba62305000000000451ac63acccdf1f67", "ab536a6363", 2, -27393525, "4810b2f603b4e19f35e8590becb2f6689bcf29404b28e444f047214ffb5fdf9e"], + ["83a583d204d926f2ee587a83dd526cf1e25a44bb668e45370798f91a2907d184f7cddcbbc7030000000700ab6565536a539f71d3776300dffdfa0cdd1c3784c9a1f773e34041ca400193612341a9c42df64e3f550e01000000050052515251ffffffff52dab2034ab0648553a1bb8fc4e924b2c89ed97c18dfc8a63e248b454035564b01000000015139ab54708c7d4d2c2886290f08a5221cf69592a810fd1979d7b63d35c271961e710424fd0300000005ac65ac5251ffffffff01168f7c030000000000a85e5fb0", "6a536353656a00", 0, 179595281, "70a688dfb8a6fb47f263720931146ba33e5cc6ae5b8bbf9cdc8b3d4078dbf381"], + ["ffd35d51042f290108fcb6ea49a560ba0a6560f9181da7453a55dfdbdfe672dc800b39e7320200000006630065516a65f2166db2e3827f44457e86dddfd27a8af3a19074e216348daa0204717d61825f198ec0030100000006ab51abab00abffffffffdf41807adb7dff7db9f14d95fd6dc4e65f8402c002d009a3f1ddedf6f4895fc8030000000500ab006a65a5a848345052f860620abd5fcd074195548ce3bd0839fa9ad8642ed80627bf43a0d47dbd010000000765ab006a656a53b38cdd6502a186da05000000000765ab00ab006a53527c0e0100000000085365ab51acacac52534bd1b1", "6a635253ac0000", 0, 1095082149, "3c05473a816621a3613f0e903faa1a1e44891dd40862b029e41fc520776350fa"], + ["6c9a4b98013c8f1cae1b1df9f0f2de518d0c50206a0ab871603ac682155504c0e0ce946f460100000000ffffffff04e9266305000000000753535100ac6aacded39e04000000000365ac6ab93ccd010000000002515397bf3d050000000003ab636300000000", "63520052ac656353", 0, -352633155, "936eff8cdfd771be24124da87c7b24feb48da7cbc2c25fb5ba13d1a23255d902"], + ["e01dc7f0021dc07928906b2946ca3e9ac95f14ad4026887101e2d722c26982c27dc2b59fdb0000000005ac5200516ab5a31ffadcbe74957a5a3f97d7f1475cc6423fc6dbc4f96471bd44c70cc736e7dec0d1ea020000000951636a526a52abac53ffffffff04bc2edd05000000000252ab528c7b02000000000952ac51526500525353324820040000000002005380c713000000000009630065ab00ac525252451bbb48", "53ab65ac", 0, -552384482, "3af5841ab44d8c8366672a5822d432645a25bd6af34291dbada82d5a10b7c2b1"], + ["009046a1023f266d0113556d604931374d7932b4d6a7952d08fbd9c9b87cbd83f4f4c178b4030000000452ac526346e73b438c4516c60edd5488023131f07acb5f9ea1540b3e84de92f4e3c432289781ea4900000000046500655357dfd6da02baef910100000000026a007d101703000000000800516500abacac5100000000", "6aab6553ac", 0, -802456669, "6a789ff41f2198106fc7ccffb323fe01fd96a19e09b5842e70d4539579c85d37"], + ["df76ec0801a3fcf3d18862c5f686b878266dd5083f16cf655facab888b4cb3123b3ce5db7e01000000010010e7ac6a0233c83803000000000365ac51faf14a040000000004ac51655100000000", "6353acab", 0, 15705861, "e7d873aa079a19ec712b269a37d2670f60d8cb334c4f97e2e3fd10eeb8ee5f5e"], + ["828fd3e0031084051ccef9cfdd97fae4d9cc50c0dae36bd22a3ff332881f17e9756c3e288e0200000004ab535363961a2ccccaf0218ec6a16ba0c1d8b5e93cfd025c95b6e72bc629ec0a3f47da7a4c396dad01000000025353ffffffff19ad28747fb32b4caf7b5dbd9b2da5a264bedb6c86d3a4805cd294ae53a86ac40200000009ab53535351ab6551abffffffff04a41650030000000005656aab6aab8331a304000000000700516365ac516a0d2a47010000000007abac516353abacdebc19040000000006ab5300636a6300000000", "51ab52ab53ac52", 0, 1866105916, "23f0e2c6496ee0738e7b538afee22119308129d370e4361583073b9e84636e75"], + ["c4b80f850323022205b3e1582f1ed097911a81be593471a8dce93d5c3a7bded92ef6c7c1260100000002006affffffff70294d62f37c3da7c5eae5d67dce6e1b28fedd7316d03f4f48e1829f78a88ae801000000096a5200530000516351f6b7b544f7c39189d3a2106ca58ce4130605328ce7795204be592a90acd81bef517d6f170200000000ffffffff012ab8080000000000075100006365006335454c1e", "53ac6a536aacac", 0, -1124103895, "06277201504e6bf8b8c94136fad81b6e3dadacb9d4a2c21a8e10017bfa929e0e"], + ["8ab69ed50351b47b6e04ac05e12320984a63801716739ed7a940b3429c9c9fed44d3398ad40300000006536a516a52638171ef3a46a2adb8025a4884b453889bc457d63499971307a7e834b0e76eec69c943038a0300000000ffffffff566bb96f94904ed8d43d9d44a4a6301073cef2c011bf5a12a89bedbaa03e4724030000000265acb606affd01edea38050000000008515252516aacac6300000000", "65000000006365ac53", 0, -1338942913, "99e03b6d49cf95acb428234e6cd93f48891c6b5a94c03513c5607a39c6453d64"], + ["2484991e047f1cf3cfe38eab071f915fe86ebd45d111463b315217bf9481daf0e0d10902a402000000006e71a424eb1347ffa638363604c0d5eccbc90447ff371e000bf52fc743ec832851bb564a0100000001abffffffffef7d014fad3ae7927948edbbb3afe247c1bcbe7c4c8f5d6cf97c799696412612020000000851536a5353006a001dfee0d7a0dd46ada63b925709e141863f7338f34f7aebde85d39268ae21b77c3068c01d0000000008535151ab00636563ffffffff018478070200000000095200635365ac52ab5341b08cd3", "", 3, 265623859, "ab5f64cb43ab902ba5af0732245592bd92096776209f7a1fa5ebbd3ad3a03c0f"], + ["54839ef9026f65db30fc9cfcb71f5f84d7bb3c48731ab9d63351a1b3c7bc1e7da22bbd508e0300000000442ad138f170e446d427d1f64040016032f36d8325c3b2f7a4078766bdd8fb106e52e8d20000000003656500ffffffff02219aa101000000000851ababac52ab00659646bd02000000000552acacabac24c394a5", "ac", 0, 906807433, "8dc62dc48491c3063803b2ed708ec694b433c0b1f26a26354a242c490d72e9e2"], + ["5036d7080434eb4eef93efda86b9131b0b4c6a0c421e1e5feb099a28ff9dd8477728639f77030000000951516aab535152ab5391429be9cce85d9f3d358c5605cf8c3666f034af42740e94d495e28b9aaa1001ba0c87580300000008006552ab00ab006affffffffd838978e10c0c78f1cd0a0830d6815f38cdcc631408649c32a25170099669daa0000000002acab8984227e804ad268b5b367285edcdf102d382d027789250a2c0641892b480c21bf84e3fb0100000000b518041e023d8653010000000001004040fb0100000000080051ac5200636a6300000000", "52ac", 0, 366357656, "bd0e88829afa6bdc1e192bb8b2d9d14db69298a4d81d464cbd34df0302c634c6"], + ["9ad5ccf503fa4facf6a27b538bc910cce83c118d6dfd82f3fb1b8ae364a1aff4dcefabd38f03000000096365655263ac655300807c48130c5937190a996105a69a8eba585e0bd32fadfc57d24029cbed6446d30ebc1f100100000004000053650f0ccfca1356768df7f9210cbf078a53c72e0712736d9a7a238e0115faac0ca383f219d0010000000600ab536552002799982b0221b8280000000000000c41320000000000086552ac6365636a6595f233a3", "6a5152", 2, 553208588, "f99c29a79f1d73d2a69c59abbb5798e987639e36d4c44125d8dc78a94ddcfb13"], + ["669538a204047214ce058aed6a07ca5ad4866c821c41ac1642c7d63ed0054f84677077a84f030000000853abacab6a655353ffffffff70c2a071c115282924e3cb678b13800c1d29b6a028b3c989a598c491bc7c76c5030000000752ac52ac5163ac80420e8a6e43d39af0163271580df6b936237f15de998e9589ec39fe717553d415ac02a4030000000463635153184ad8a5a4e69a8969f71288c331aff3c2b7d1b677d2ebafad47234840454b624bf7ac1d03000000056a63abab63df38c24a02fbc63a040000000002ab535ec3dc050000000002536500000000", "635153", 3, -190399351, "9615541884dfb1feeb08073a6a6aa73ef694bc5076e52187fdf4138a369f94d9"], + ["a7f139e502af5894be88158853b7cbea49ba08417fbbca876ca6614b5a41432be34499987b000000000765635165abac63ffffffff8b8d70e96c7f54eb70da0229b548ced438e1ca2ba5ddd648a027f72277ee1efc0100000001abffffffff044f2c4204000000000165e93f550100000000050000526a6a94550304000000000365536aadc21c0300000000016300000000", "6aacac6363ab5265ac", 1, 2143189425, "6e3f97955490d93d6a107c18d7fe402f1cada79993bb0ff0d096357261b3a724"], + ["3b94438f0366f9f53579a9989b86a95d134256ce271da63ca7cd16f7dd5e4bffa17d35133f010000000100ffffffff1aaad0c721e06ec00d07e61a84fb6dc840b9a968002ce7e142f943f06fd143a10100000008535151ac51ab0053b68b8e9c672daf66041332163e04db3f6048534bd718e1940b3fc3811c4eef5b7a56888b01000000001d58e38c012e38e700000000000852ab53ac6365536a00000000", "ab655352", 1, -935223368, "d018087157f556746765e628c9fd5a8520b93d4c55453eb6260f595e17065db0"], + ["e5dca8a20456de0a67e185fa6ea94085ceae478d2c15c73cb931a500db3a1b6735dd1649ec0200000005ab536aabab32d11bbdcb81361202681df06a6b824b12b5cb40bb1a672cf9af8f2a836e4d95b7839327030000000951005365ab65abacabb345085932939eef0c724adef8a57f9e1bf5813852d957c039b6a12d9c2f201ea520fb030000000009ac5352005165acac6a5efc6072f1a421dc7dc714fc6368f6d763a5d76d0278b95fc0503b9268ccfadb48213a2500000000026a53ffffffff039ee1c4020000000009ac5353ab6353535163184018000000000005655265526a9a4a8a050000000001ac00000000", "65ab53ab6a00ab6553", 2, 1902561212, "7928ae8e86c0b0cad1b2c120ea313087437974382ee6d46443ca5ac3f5878b88"], + ["972128b904e7b673517e96e98d80c0c8ceceae76e2f5c126d63da77ffd7893fb53308bb2da0300000006ac6552ab52acffffffff4cac767c797d297c079a93d06dc8569f016b4bf7a7d79b605c526e1d36a40e2202000000095365ab636aac6a6a6a69928d2eddc836133a690cfb72ec2d3115bf50fb3b0d10708fa5d2ebb09b4810c426a1db01000000060052526300001e8e89585da7e77b2dd2e30625887f0660accdf29e53a614d23cf698e6fc8ab03310e87700000000076a520051acac6555231ddb0330ec2d03000000000200abfaf457040000000004ab6a6352bdc42400000000000153d6dd2f04", "", 0, 209234698, "4a92fec1eb03f5bd754ee9bfd70707dc4420cc13737374f4675f48529be518e4"], + ["1fb4085b022c6cfb848f8af7ba3ba8d21bd23ffa9f0bfd181cb68bcaaf2074e66d4974a31602000000090000006a6a6500acab6c12c07d9f3dbd2d93295c3a49e3757119767097e7fd5371f7d1ba9ba32f1a67a5a426f00000000000ffffffff018fd2fc04000000000363ac5100000000", "65ab006a6aab526a", 0, 1431502235, "6795f09b9f0098df92e711e698254969856ce6c2c429ecfa818f8c660d0e94ab"], + ["5374f0c603d727f63006078bd6c3dce48bd5d0a4b6ea00a47e5832292d86af258ea0825c260000000009655353636352526a6af2221067297d42a9f8933dfe07f61a574048ff9d3a44a3535cd8eb7de79fb7c45b6f47320200000003ac006affffffff153d917c447d367e75693c5591e0abf4c94bbdd88a98ab8ad7f75bfe69a08c470200000005ac65516365ffffffff037b5b7b000000000001515dc4d904000000000004bb26010000000004536a6aac00000000", "516552516352ac", 2, 328538756, "8bb7a0129eaf4b8fc23e911c531b9b7637a21ab11a246352c6c053ff6e93fcb6"], + ["c441132102cc82101b6f31c1025066ab089f28108c95f18fa67db179610247086350c163bd010000000651525263ab00ffffffff9b8d56b1f16746f075249b215bdb3516cbbe190fef6292c75b1ad8a8988897c3000000000751ab6553abab00ffffffff02f9078b000000000009ab0053ac51ac00ab51c0422105000000000651006563525200000000", "ac51", 0, -197051854, "ca747ff3cc54dda0d7629cf8b53e2203188fbd50580492fba1c99239f5a6f258"], + ["ab82ad3b04545bd86b3bb937eb1af304d3ef1a6d1343ed809b4346cafb79b7297c09e1648202000000086351ac5200535353ffffffff95d32795bbaaf5977a81c2128a9ec0b3c7551b9b1c3d952876fcb423b2dfb9e80000000005515363acac47a7d050ec1a603627ce6cd606b3af314fa7964abcc579d92e19c7aba00cf6c3090d6d4601000000056a516551633e794768bfe39277ebc0db18b5afb5f0c8117dde9b4dfd5697e9027210eca76a9be20d63000000000700520063ab6aacffffffff01ec2ddc050000000008ac52ac65ac65ac5100000000", "536300abab", 1, -2070209905, "aeaa27fe3521c2dbc176da5618ae0dd269d5bd556be5ec236f1b6ff3a5108146"], + ["8bff9d170419fa6d556c65fa227a185fe066efc1decf8a1c490bc5cbb9f742d68da2ab7f320100000007ab000053525365a7a43a80ab9593b9e8b6130a7849603b14b5c9397a190008d89d362250c3a2257504eb810200000007acabacac00ab51ee141be418f003e75b127fd3883dbf4e8c3f6cd05ca4afcaac52edd25dd3027ae70a62a00000000008ac52526a5200536affffffffb8058f4e1d7f220a1d1fa17e96d81dfb9a304a2de4e004250c9a576963a586ae0300000005abacac5363b9bc856c039c01d804000000000951656aac53005365acb0724e00000000000565abab63acea7c7a0000000000036a00ac00000000", "6565", 1, -1349282148, "c48e6026706e649e3da9ed785cb09f152daa9d68192e6678dd2035e449bbeb59"], + ["0e1633b4041c50f656e882a53fde964e7f0c853b0ada0964fc89ae124a2b7ffc5bc97ea6230100000006ac6aacacabacffffffff2e35f4dfcad2d53ea1c8ada8041d13ea6c65880860d96a14835b025f76b1fbd9000000000351515121270867ef6bf63a91adbaf790a43465c61a096acc5a776b8e5215d4e5cd1492e611f761000000000600ac6aab5265ffffffff63b5fc39bcac83ca80ac36124abafc5caee608f9f63a12479b68473bd4bae769000000000965ac52acac5263acabffffffff0163153e020000000008ab005165ab65515300000000", "6a6aac00", 0, -968477926, "79ad74dfe1f6968b0000374ffa9872973eb3af78640952c258612b9006542142"], + ["2b052c24022369e956a8d318e38780ef73b487ba6a8f674a56bdb80a9a63634c6110fb5154010000000251acffffffff48fe138fb7fdaa014d67044bc05940f4127e70c113c6744fbd13f8d51d45143e01000000005710db3804e01aa9030000000008acac6a516a5152abfd55aa01000000000751ab510000ac636d6026010000000000b97da9000000000000fddf3b53", "006552", 0, 595461670, "685d67d84755906d67a007a7d4fa311519467b9bdc6a351913246a41e082a29f"], + ["073bc856015245f03b2ea2da62ccedc44ecb99e4250c7042f596bcb23b294c9dc92cfceb6b02000000095163abab52abab636afe292fb303b7c3f001000000000352636af3c49502000000000400ac6a535851850100000000066aac6553ab6500000000", "ab6aab53006aab52", 0, 247114253, "fa767439529b11770cae895405c50146a0f1410aea0a400cd49f3504558e0b9b"], + ["7888b71403f6d522e414d4ca2e12786247acf3e78f1918f6d727d081a79813d129ee8befce0100000009ab516a6353ab6365abffffffff4a882791bf6400fda7a8209fb2c83c6eef51831bdf0f5dacde648859090797ec030000000153ffffffffbb08957d59fa15303b681bad19ccf670d7d913697a2f4f51584bf85fcf91f1f30200000008526565ac52ac63acffffffff0227c0e8050000000001ac361dc801000000000800515165ab00ab0000000000", "656a", 2, 1869281295, "f43378a0b7822ad672773944884e866d7a46579ee34f9afc17b20afc1f6cf197"], + ["cc4dda57047bd0ca6806243a6a4b108f7ced43d8042a1acaa28083c9160911cf47eab910c40200000007526a0000ab6a63e4154e581fcf52567836c9a455e8b41b162a78c85906ccc1c2b2b300b4c69caaaa2ba0230300000008ab5152ac5100ab65ffffffff69696b523ed4bd41ecd4d65b4af73c9cf77edf0e066138712a8e60a04614ea1c0300000004ab6a000016c9045c7df7836e05ac4b2e397e2dd72a5708f4a8bf6d2bc36adc5af3cacefcf074b8b403000000065352ac5252acffffffff01d7e380050000000000cf4e699a", "525163656351", 1, -776533758, "ec3ea2460a90bbf5951f992f8addfda3193771cb0dd1ebe989b50f83772225e8"], + ["b7877f82019c832707a60cf14fba44cfa254d787501fdd676bd58c744f6e951dbba0b3b77f0200000009ac515263ac53525300a5a36e500148f89c0500000000085265ac6a6a65acab00000000", "6563", 0, -1785108479, "fced4b7db7979bb3e9a1a6ade1580d51f83af0121ff00eb0be254060f9b95c03"], + ["aeb14046045a28cc59f244c2347134d3434faaf980961019a084f7547218785a2bd03916f3000000000165f852e6104304955bda5fa0b75826ee176211acc4a78209816bbb4419feff984377b2352200000000003a94a5032df1e0d60390715b4b188c330e4bb7b995f07cdef11ced9d17ee0f60bb7ffc8e0100000002516513e343a5c1dc1c80cd4561e9dddad22391a2dbf9c8d2b6048e519343ca1925a9c6f0800a020000000665516365ac513180144a0290db27000000000006ab655151ab5138b187010000000007ab5363abac516a9e5cd98a", "53ac", 0, 478591256, "027f6cec86a94d565e9e02fffe6f8f256829e4c353f158aa489f305435a0433c"], + ["c9270fe004c7911b791a00999d108ce42f9f1b19ec59143f7b7b04a67400888808487bd59103000000066a0052ac6565b905e76687be2dd7723b22c5e8269bc0f2000a332a289cfc40bc0d617cfe3214a61a85a30300000007ac63ac00635251560871209f21eb0268f175b8b4a06edd0b04162a974cf8b5dada43e499a1f22380d35ede0300000000792213fc58b6342cc8100079f9f5f046fb89f2d92cf0a2cb6d07304d32d9da858757037c0000000008abab51636565516affffffff02c72a8b03000000000452acac530dfb9f05000000000096f94307", "5253ab536351", 3, 543688372, "17158be65bc3936774b916284fceadebffcf516f39a1d51e6590cc51ad5a9020"], + ["57a5a04c0278c8c8e243d2df4bb716f81d41ac41e2df153e7096f5682380c4f441888d9d260300000004ab63ab6afdbe4203525dff42a7b1e628fe22bccaa5edbb34d8ab02faff198e085580ea5fcdb0c61b0000000002ac6affffffff03375e6c05000000000663ab516a6a513cb6260400000000007ca328020000000006516a636a52ab94701cc7", "0053ac5152", 0, -550925690, "4b74edf83ef30bc099ea2004c9fe7f7383b948a1485913ced4695fea0e4b2d86"], + ["072b75a504ad2550c2e9a02614bc9b2a2f50b5b553af7b87c0ef07c64ddc8d8934c96d216401000000036aabaca1387242a5bcd21099b016ad6045bed7dce603472757d9822cc5f602caa4ae20414d378b02000000026a63e4ac816734acdc969538d6f70b8ab43a2589f55e0177a4dc471bdd0eb61d59f0f46f6bb801000000065351526aab52d9f2977be76a492c3a7617b7a16dc29a3b0a7618f328c2f7d4fd9bafe760dc427a5066ef000000000465635165ffffffff02c5793600000000000165296820050000000002ac6300000000", "53006a6aac0052ab", 2, 66084636, "437e89bb6f70fd2ed2feef33350b6f6483b891305e574da03e580b3efd81ae13"], + ["7e27c42d0279c1a05eeb9b9faedcc9be0cab6303bde351a19e5cbb26dd0d594b9d74f40d2b020000000200518c8689a08a01e862d5c4dcb294a2331912ff11c13785be7dce3092f154a005624970f84e0200000000500cf5a601e74c1f0000000000076aab52636a6a5200000000", "6500006a5351", 0, 449533327, "c1027047fde2a87e7155afe0464b0bcbc44e1e29d4ee443df85355c7438138d8"], + ["11414de403d7f6c0135a9df01cb108c1359b8d4e105be50a3dcba5e6be595c8817217490b20000000003005263ffffffff0c6becb9c3ad301c8dcd92f5cbc07c8bed7973573806d1489316fc77a829da03030000000700005253535352ffffffff2346d74ff9e12e5111aa8779a2025981850d4bf788a48de72baa2e321e4bc9ca00000000056352acab63cc585b64045e0385050000000009ab5253ab516aacac00efa9cf0300000000065200635151acbe80330400000000070063635100ab000be159050000000007525300655300ac00000000", "51656a0051ab", 0, 683137826, "d4737f3b58f3e5081b35f36f91acde89dda00a6a09d447e516b523e7a99264d5"], + ["1c6b5f29033fc139338658237a42456123727c8430019ca25bd71c6168a9e35a2bf54538d80100000008536aac52ac6a6a52ffffffff3fb36be74036ff0c940a0247c451d923c65f826793d0ac2bb3f01ecbec8033290100000007ab000051ab6363ffffffff5d9eca0cf711685105bd060bf7a67321eaef95367acffab36ce8dedddd632ee2000000000652ac6a63ac517167319e032d26de040000000003516363dc38fb010000000000b37b00000000000006ab520051ac534baba51f", "636300ababac6563", 0, -2049129935, "3282a2ec6b8c87c9303e6060c17b421687db1bd35fbfa0345b48f2490e15b6cc"], + ["978b9dad0214cfc7ce392d74d9dcc507350dc34007d72e4125861c63071ebf2cc0a6fd4856020000000651ac6a6aab52ffffffff47f20734e3370e733f87a6edab95a7a268ae44db7a8974e255614836b22938720200000008635265ac51516553ffffffff0137b2560100000000035252ac2f3363e9", "006aab6352", 1, 2014249737, "fda93a4a94c3650d07d9ecb67f1bf065c61ddd37bf334c6c92b58ab064dddade"], + ["442f1c8703ab39876153c241ab3d69f432ba6db4732bea5002be45c8ca10c3a2356fe0e9590300000001accb2b679cab7c58a660cb6d4b3452c21cd7251a1b77a52c300f655f5baeb6fa27ff5b79880300000003005252e5ccf55712bc8ed6179f6726f8a78f3018a7a0391594b7e286ef5ee99efdcde302a102cc0200000009006352526351536a63ffffffff04443f63030000000006536a63ab63651405fb020000000009ac535351525300ab6a9f172b000000000004ab535263ad5c50050000000008656a65ab630000ac00000000", "65636aab006552", 2, 2125838230, "8c5fa66569f3b4405f800f60b146fec2f74f69109462eb62b8c83fc2871cc73c"], + ["2b3470dd028083910117f86614cdcfb459ee56d876572510be4df24c72e8f58c70d5f5948b03000000066aab65635265da2c3aac9d42c9baafd4b655c2f3efc181784d8cba5418e053482132ee798408ba43ccf90300000000ffffffff047dda4703000000000765516a52ac53009384a603000000000651636a63ab6a8cf57a03000000000352ab6a8cf6a405000000000952636a6a6565525100661e09cb", "ac520063ac6a6a52", 1, 1405647119, "29e2fe1ec14490dfa4a53d017a6d10b747813c30ba3489bae3e7e5d80e5d3f3d"], + ["d74282b501be95d3c19a5d9da3d49c8a88a7049c573f3788f2c42fc6fa594f59715560b9b00000000009655353525265ac52ac9772121f028f8303030000000003510065af5f47040000000007ac516a6551630000000000", "acab53006363ac", 0, -1113209834, "c2d08c4e5f48a0de8e11cbaf4e989fd17aed5fe3c1860296e9225c050f1c0d98"], + ["3a5644a9010f199f253f858d65782d3caec0ac64c3262b56893022b9796086275c9d4d097b02000000009d168f7603a67b30050000000007ac51536a0053acd9d88a050000000007655363535263ab3cf1f403000000000352ac6a00000000", "005363536565acac6a", 0, -1383947259, "a8af8430fa3def3ba3eb0753716f6beeb1c8ff449544919a7427c42b2945c288"], + ["67b3cc43049d13007485a8133b90d94648bcf30e83ba174f5486ab42c9107c69c5530c5e1f0000000003005100ffffffff9870ebb65c14263282ea8d41e4f4f40df16b565c2cf86f1d22a9494cad03a67f01000000016a5a121bee5e359da548e808ae1ad6dfccae7c67cbb8898d811638a1f455a671e822f228ef030000000151c1fcc9f9825f27c0dde27ea709da62a80a2ff9f6b1b86a5874c50d6c37d39ae31fb6c8a0030000000163553b8786020ca74a00000000000665635153ab5275c0760000000000020052e659b05d", "636aab6a6a", 0, -342795515, "33012f9cf0093828a9e51d5abde84bd4a886963a302b53b0cf15b6db1de25c15"], + ["bda1ff6804a3c228b7a12799a4c20917301dd501c67847d35da497533a606701ad31bf9d5e0300000001ac16a6c5d03cf516cd7364e4cbbf5aeccd62f8fd03cb6675883a0636a7daeb650423cb1291010000000500656553ac4a63c30b6a835606909c9efbae1b2597e9db020c5ecfc0642da6dc583fba4e84167539a8020000000865525353515200acffffffff990807720a5803c305b7da08a9f24b92abe343c42ac9e917a84e1f335aad785d00000000026a52ffffffff04981f20030000000001ab8c762200000000000253ab690b9605000000000151ce88b301000000000753526a6a51006500000000", "000052ac52530000", 1, -1809193204, "f8ad12b8106d1f431d912315605a6d8909e2e04bc4d7ba533d6d90752c183b91"], + ["2ead28ff0243b3ab285e5d1067f0ec8724224402b21b9cef9be962a8b0d153d401be99bbee0000000004ac635153ffffffff6985987b7c1360c9fa8406dd6e0a61141709f0d5195f946da55ed83be4e3895301000000020053ffffffff016503d20500000000085251ac6a65656a6a00000000", "51abab", 1, 1723793339, "45cdc25938183c079490171559f78c7245692f98297e2bf5f8958f95d193ffcf"], + ["db4904e6026b6dd8d898f278c6428a176410d1ffbde75a4fa37cda12263108ccd4ca6137440100000007656a0000515263ffffffff1db7d5005c1c40da0ed17b74cf6b2a6ee2c33c9e0bacda76c0da2017dcac2fc70200000004abab6a53ffffffff0454cf2103000000000153463aef000000000009ab6a630065ab52636387e0ed050000000000e8d16f05000000000352ac63e4521b22", "", 1, 1027042360, "bfa20b7d9c36929bbfba46a9ed89fc14ff2288667ecef0ad1e0b6238def92cb5"], + ["dca31ad10461ead74751e83d9a81dcee08db778d3d79ad9a6d079cfdb93919ac1b0b61871102000000086500525365ab51ac7f7e9aed78e1ef8d213d40a1c50145403d196019985c837ffe83836222fe3e5955e177e70100000006525152525300ffffffff5e98482883cc08a6fe946f674cca479822f0576a43bf4113de9cbf414ca628060100000006ac53516a5253ffffffff07490b0b898198ec16c23b75d606e14fa16aa3107ef9818594f72d5776805ec502000000036a0052ffffffff01932a2803000000000865ab6551ac6a516a2687aa06", "635300ac", 2, -1880362326, "74d6a2fa7866fd8b74b2e34693e2d6fd690410384b7afdcd6461b1ae71d265ce"], + ["e14e1a9f0442ab44dfc5f6d945ad1ff8a376bc966aad5515421e96ddbe49e529614995cafc03000000055165515165fffffffff97582b8290e5a5cfeb2b0f018882dbe1b43f60b7f45e4dd21dbd3a8b0cfca3b0200000000daa267726fe075db282d694b9fee7d6216d17a8c1f00b2229085495c5dc5b260c8f8cd5d000000000363ac6affffffffaab083d22d0465471c896a438c6ac3abf4d383ae79420617a8e0ba8b9baa872b010000000963526563ac5363ababd948b5ce022113440200000000076a636552006a53229017040000000000e6f62ac8", "526353636a65", 3, -485265089, "4e881eef38067be04a9bc652b9d95cbf484b6dfbc691433c3e9391144bee2cc5"], + ["720d4693025ca3d347360e219e9bc746ef8f7bc88e8795162e5e2f0b0fc99dc17116fc937100000000046353520045cb1fd79824a100d30b6946eab9b219daea2b0cdca6c86367c0c36af98f19ac64f3575002000000008a1c881003ed16f3050000000008536a63630000abac45e0e704000000000151f6551a05000000000963536565515363abab00000000", "6553ab6a6a510000ab", 1, 1249091329, "6e28c09d2586c3649084a499fac69155010f53bb083645dbcc6adb711257d9a6"], + ["69df842a04c1410bfca10896467ce664cfa31c681a5dac10106b34d4b9d4d6d0dc1eac01c1000000000551536a5165269835ca4ad7268667b16d0a2df154ec81e304290d5ed69e0069b43f8c89e673328005e200000000076a5153006aacabffffffffc9314bd80b176488f3d634360fcba90c3a659e74a52e100ac91d3897072e3509010000000765abac51636363ffffffff0e0768b13f10f0fbd2fa3f68e4b4841809b3b5ba0e53987c3aaffcf09eee12bf0300000008ac535263526a53ac514f4c2402da8fab0400000000001ef15201000000000451526a52d0ec9aca", "525365ac52", 1, 313966985, "7caa24564c335381bcc6066e6eeacb96c4d4e8546f32ef51dc487dfa8e500e64"], + ["adf2340d03af5c589cb5d28c06635ac07dd0757b884d4777ba85a6a7c410408ad5efa8b19001000000045100ab00ffffffff808dc0231c96e6667c04786865727013922bcb7db20739b686f0c17f5ba70e8f0300000000fd2332a654b580881a5e2bfec8313f5aa878ae94312f37441bf2d226e7fc953dcf0c77ab000000000163aa73dc580412f8c2050000000005636aacac63da02d502000000000153e74b52020000000001536b293d030000000009636552ababacab526500000000", "000052ab52ababab", 0, -568651239, "7a977fec8dacbca305a6b60ee2820023ea687cc9ee8155da0e3ab32efce495d0"], + ["e4fec9f10378a95199c1dd23c6228732c9de0d7997bf1c83918a5cfd36012476c0c3cba24002000000085165536500ac0000ad08ab93fb49d77d12a7ccdbb596bc5110876451b53a79fdce43104ff1c316ad63501de801000000046a6352ab76af9908463444aeecd32516a04dd5803e02680ed7f16307242a794024d93287595250f4000000000089807279041a82e603000000000200521429100200000000055253636a63f20b940400000000004049ed04000000000500ab5265ab43dfaf7d", "6563526aac", 2, -1923470432, "10a3d6e7339c8aa4b26b5ae84a28aaee18322e08f1e1075a7af91f45e75a94b4"], + ["4000d3600100b7a3ff5b41ec8d6ccdc8b2775ad034765bad505192f05d1f55d2bc39d0cbe10100000007ab5165ac6a5163ffffffff034949150100000000026a6a92c9f6000000000008ab6553ab6aab635200e697040000000007636a5353525365237ae7d2", "52000063", 0, -880046683, "c76146f68f43037289aaeb2bacf47408cddc0fb326b350eb4f5ef6f0f8564793"], + ["eabc0aa701fe489c0e4e6222d72b52f083166b49d63ad1410fb98caed027b6a71c02ab830c03000000075253ab63530065ffffffff01a5dc0b05000000000253533e820177", "", 0, 954499219, "47cd08a50974cfbbb94f1a7121ac9f45058722afe7ecc245ca5d759892e71ead"], + ["d48d55d304aad0139783b44789a771539d052db565379f668def5084daba0dfd348f7dcf6b00000000006826f59e5ffba0dd0ccbac89c1e2d69a346531d7f995dea2ca6d7e6d9225d81aec257c6003000000096a655200ac656552acffffffffa188ffbd5365cae844c8e0dea6213c4d1b2407274ae287b769ab0bf293e049eb0300000005ac6a6aab51ad1c407c5b116ca8f65ed496b476183f85f072c5f8a0193a4273e2015b1cc288bf03e9e2030000000252abffffffff04076f44040000000006655353abab53be6500050000000003ac65ac3c15040500000000095100ab536353516a52ed3aba04000000000900ac53ab53636aabac00000000", "5253526563acac", 2, -1506108646, "bbee17c8582514744bab5df50012c94b0db4aff5984d2e13a8d09421674404e2"], + ["9746f45b039bfe723258fdb6be77eb85917af808211eb9d43b15475ee0b01253d33fc3bfc502000000065163006a655312b12562dc9c54e11299210266428632a7d0ee31d04dfc7375dcad2da6e9c11947ced0e000000000009074095a5ac4df057554566dd04740c61490e1d3826000ad9d8f777a93373c8dddc4918a00000000025351ffffffff01287564030000000004636a00ab00000000", "52", 2, -1380411075, "84af1623366c4db68d81f452b86346832344734492b9c23fbb89015e516c60b2"], + ["8731b64903d735ba16da64af537eaf487b57d73977f390baac57c7b567cb2770dfa2ef65870100000001635aedd990c42645482340eacb0bfa4a0a9e888057389c728b5b6a8691cdeb1a6a67b45e140200000008ac53526a52516551ffffffff45c4f567c47b8d999916fd49642cbc5d10d43c304b99e32d044d35091679cb860100000003006a51ffffffff0176d6c200000000000000000000", "ab6a65ab53", 2, -1221546710, "ccfdba36d9445f4451fb7cbf0752cc89c23d4fc6fff0f3930d20e116f9db0b95"], + ["f5cfc52f016209ab1385e890c2865a74e93076595d1ca77cbe8fbf2022a2f2061a90fb0f3e010000000253acffffffff027de73f0200000000085252ac510052acac49cd6a020000000000e6c2cb56", "516552535300ab63", 0, -1195302768, "232ac0146cd8f9c3af1e5f7768fc5d1355afc05914e1cee48a84353759a31c5f"], + ["df0a32ae01c4672fd1abd0b2623aae0a1a8256028df57e532f9a472d1a9ceb194267b6ee190200000009536a6a51516a525251b545f9e803469a2302000000000465526500810631040000000000441f5b050000000006530051006aaceb183c76", "536a635252ac6a", 0, 1601138049, "0598d898ca69f7e7369be7b579e19a8714cdecc3d3e7591fc50edcc561b09169"], + ["d102d10c028b9c721abb259fe70bc68962f6cae384dabd77477c59cbeb1fb26266e091ba3e0100000002516affffffffe8d7305a74f43e30c772109849f4cd6fb867c7216e6d92e27605e69a0818899700000000026a65ecf82d58027db4620500000000026552c28ed3010000000001ab00000000", "0051ab515365", 1, -131815524, "dcee326485a50c9c94848ecf898409e194dd169a0a458da0dac4c9eddbb1affc"], + ["cef930ed01c36fcb1d62ceef931bef57098f27a77a4299904cc0cbb44504802d535fb11557010000000153ffffffff02c8657403000000000863ac655253520063d593380400000000046aab536a00000000", "656a0051ab6365ab53", 0, -351313372, "d774dd493e69ecd80ca79eb4aa33826f72e31321699fa0154057f0a9121e77d0"], + ["b1c0b71804dff30812b92eefb533ac77c4b9fdb9ab2f77120a76128d7da43ad70c20bbfb990200000002536392693e6001bc59411aebf15a3dc62a6566ec71a302141b0c730a3ecc8de5d76538b30f55010000000665535252ac514b740c6271fb9fe69fdf82bf98b459a7faa8a3b62f3af34943ad55df4881e0d93d3ce0ac0200000000c4158866eb9fb73da252102d1e64a3ce611b52e873533be43e6883137d0aaa0f63966f060000000001abffffffff04a605b604000000000851006a656a630052f49a0300000000000252515a94e1050000000009abac65ab0052abab00fd8dd002000000000651535163526a2566852d", "ac5363", 0, -1718831581, "d910acf2c7b66b349802c7a368cf25ef4da81675eaee79ba7f3646889fd00174"], + ["6a270ee404ebc8d137cfd4bb6b92aa3702213a3139a579c1fc6f56fbc7edd9574ef17b13f30100000009ab00ab656565ababacffffffffaa65b1ab6c6d87260d9e27a472edceb7dd212483e72d90f08857abf1dbfd46d10100000000fffffffff93c4c9c84c4dbbe8a912b99a2830cfe3401aebc919041de063d660e585fc9f002000000096aabacab52ac6a53acfa6dcef3f28355a8d98eee53839455445eeee83eecd2c854e784efa53cee699dbfecaebd0100000003ab6a51ffffffff04f7d71b050000000009ac6a536aac6a6365513c37650500000000065265abab6a53fa742002000000000039ed82030000000009516aac635165ab51ab2fdabd17", "ab535252526563", 1, -1326210506, "1dec0d5eb921bf5b2df39c8576e19c38d0c17254a4a0b78ac4b5422bcc426258"], + ["3657e4260304ccdc19936e47bdf058d36167ee3d4eb145c52b224eff04c9eb5d1b4e434dfc0000000001ab58aefe57707c66328d3cceef2e6f56ab6b7465e587410c5f73555a513ace2b232793a74400000000036a006522e69d3a785b61ad41a635d59b3a06b2780a92173f85f8ed428491d0aaa436619baa9c4501000000046351abab2609629902eb7793050000000000a1b967040000000003525353a34d6192", "516a", 0, -1761874777, "e5d4584600fe420e178a4207fffdf95b787c447798bc9fa4cb3e651b327adac6"], + ["a0eb6dc402994e493c787b45d1f946d267b09c596c5edde043e620ce3d59e95b2b5b93d43002000000096a5252526aac63ab6555694287a279e29ee491c177a801cd685b8744a2eab83824255a3bcd08fc0e3ea13fb8820000000009abab6365ab52ab0063ffffffff029e424a040000000008acab53ab516a636a23830f0400000000016adf49c1f9", "ac0065ac6500005252", 1, 669294500, "e05e3d383631a7ed1b78210c13c2eb26564e5577db7ddfcea2583c7c014091d4"], + ["6e67c0d3027701ef71082204c85ed63c700ef1400c65efb62ce3580d187fb348376a23e9710200000001655b91369d3155ba916a0bc6fe4f5d94cad461d899bb8aaac3699a755838bfc229d6828920010000000765536353526a52ffffffff04c0c792000000000005650052535372f79e000000000001527fc0ee010000000005ac5300ab65d1b3e902000000000251aba942b278", "6a5151", 0, 1741407676, "e657e2c8ec4ebc769ddd3198a83267b47d4f2a419fc737e813812acefad92ff7"], + ["8f53639901f1d643e01fc631f632b7a16e831d846a0184cdcda289b8fa7767f0c292eb221a00000000046a53abacffffffff037a2daa01000000000553ac6a6a51eac349020000000005ac526552638421b3040000000007006a005100ac63048a1492", "ac65", 0, 1033685559, "da86c260d42a692358f46893d6f91563985d86eeb9ea9e21cd38c2d8ffcfcc4d"], + ["491f99cb01bdfba1aa235e5538dac081fae9ce55f9622de483afe7e65105c2b0db75d360d200000000045251636340b60f0f041421330300000000096351ac000051636553ce2822040000000005516a00ac5180c8e40300000000025100caa8570400000000020000cfdc8da6", "6a5100516aab655365", 0, -953727341, "397c68803b7ce953666830b0221a5e2bcf897aa2ded8e36a6b76c497dcb1a2e1"], + ["b3cad3a7041c2c17d90a2cd994f6c37307753fa3635e9ef05ab8b1ff121ca11239a0902e700300000009ab635300006aac5163ffffffffcec91722c7468156dce4664f3c783afef147f0e6f80739c83b5f09d5a09a57040200000004516a6552ffffffff969d1c6daf8ef53a70b7cdf1b4102fb3240055a8eaeaed2489617cd84cfd56cf020000000352ab53ffffffff46598b6579494a77b593681c33422a99559b9993d77ca2fa97833508b0c169f80200000009655300655365516351ffffffff04d7ddf800000000000853536a65ac6351ab09f3420300000000056aab65abac33589d04000000000952656a65655151acac944d6f0400000000006a8004ba", "005165", 1, 1035865506, "fe1dc9e8554deecf8f50c417c670b839cc9d650722ebaaf36572418756075d58"], + ["e1cfd73b0125add9e9d699f5a45dca458355af175a7bd4486ebef28f1928d87864384d02df02000000036a0051ffffffff0357df030100000000036a5365777e2d04000000000763ab6a00005265f434a601000000000351655100000000", "ab53ab", 0, -1936500978, "18a1f4838af570ea30bf6a4e222182407de845ab84829870b62ef5a2cf4f8cbd"], + ["cf781855040a755f5ba85eef93837236b34a5d3daeb2dbbdcf58bb811828d806ed05754ab8010000000351ac53ffffffffda1e264727cf55c67f06ebcc56dfe7fa12ac2a994fecd0180ce09ee15c480f7d00000000096351516a51acac00ab53dd49ff9f334befd6d6f87f1a832cddfd826a90b78fd8cf19a52cb8287788af94e939d6020000000700525251ac526310d54a7e8900ed633f0f6f0841145aae7ee0cbbb1e2a0cae724ee4558dbabfdc58ba6855010000000552536a53abfd1b101102c51f910500000000096300656a525252656a300bee010000000009ac52005263635151abe19235c9", "53005365", 2, 1422854188, "d5981bd4467817c1330da72ddb8760d6c2556cd809264b2d85e6d274609fc3a3"], + ["fea256ce01272d125e577c0a09570a71366898280dda279b021000db1325f27edda41a53460100000002ab53c752c21c013c2b3a01000000000000000000", "65", 0, 1145543198, "3eb284f187e308f5265a6cce22ed776055a08addc4dd0f341d6e13565646ab6d"], + ["Test vectors for SIGHASH_FORKID"], + ["3eb87070042d16f9469b0080a3c1fe8de0feae345200beef8b1e0d7c62501ae0df899dca1e03000000066a0065525365ffffffffd14a9a335e8babddd89b5d0b6a0f41dd6b18848050a0fc48ce32d892e11817fd030000000863acac00535200527ff62cf3ad30d9064e180eaed5e6303950121a8086b5266b55156e4f7612f2c7ebf223e0020000000100ffffffff6273ca3aceb55931160fa7a3064682b4790ee016b4a5c0c0d101fd449dff88ba01000000055351ac526aa3b8223d0421f25b0400000000026552f92db70500000000075253516a656a53c4a908010000000000b5192901000000000652525251516aa148ca38", "acab53", 3, -1325231124, "fbbc83ed610e416d94dcee2bb3bc35dfea8060b8052c59eabd7e998e3e978328"], + ["1d23429f02b26456f634a9427bd18367dc477d496dbe9c0ec4adea5e89faa23df518b42e2e0100000006536aac6a6352b0856707c61a7ac41db9327e549fcaa7056b7a59bfac2a515c3e3a59dc8393e9b53f85fd0300000004ac6351ab6397678c0481ab6c01000000000100d9eee5040000000005ac53acac004eee220100000000030065637aaf0205000000000752536a00636aac00000000", "51006552", 1, 1523876458, "7519711b432e8d30bd5e51f660b8731b2f1f4939833fe8f9ab1daed4ae4e8449"], + ["617da8a40352a0572afdf7accebea4ce89d6afd689536c546eb70cca51897d7fc17098b55702000000066a526a5252654b6c10bc05c1abba811c86d3d558d88ff241b63975a5044bd24853bd63cb5ae44825916800000000085265acac6a00abac821b96454846291365d28a321ec1ff8fcea810c0c4fcd2eb29a23211561444957945fc4301000000076565ac6551ac6affffffff040a88c70100000000045152526aa19165030000000007525265ac53ac525fe7cd0500000000065351536565abc5af1c02000000000351000000000000", "536a", 2, 918590178, "e5c4e0b08780a0d40845972262beff78bdd7708ccfdeb5a05b7554b4b22b584e"], + ["1c4f1dba01cbcc506ca3e93f13cb2963e5f9bc6e861b23b2f7b3cbb3f9145a4dd52fa4b146000000000153a91eae9b01a445da01000000000000000000", "536a52636553635351", 0, -372992040, "07bc239bb251e99790ae8d4187c5351a51f85205bba84545b2bf99981846e956"], + ["74bb6dcd04a2ef7c3f91520c70871b59f024d3e5e6b3f56b0a946e36d4a880776aec39b4d4010000000100ffffffff32ba25f9665289c81d97131a56ca45e7ab11569e6dd39c3a098e8ffe85cee19702000000076a6a51ab52acac3888587425716c12954331979777d3d3063027fa4e1a471baa089983c5c7ddb71c26b6290200000007ac6a6a5200ab6a0bf02381927133b6ed072c507ec03e12660887ba09c5f9748598c97033f7ff87c68b55cc0200000001acffffffff03a5bcc802000000000153c66e45000000000009636a6a536a63ab5352f9b4d8050000000000ed8227b8", "536a6363", 1, -165802784, "58f4c0f2dc2692e224550d7e9a2bd2161655bc1b3fcebf95f33742cbd7cdfd89"], + ["daf41ebc02afd05cc3e396f29965f45e8dc12615d4b37b5fb926da0683758b1cead144214c0300000004ac65ac6a77b96b596eaedf4b3598336f3d70791cfce039642a1d510c1b8abd21d73130b4f67c02530000000009ac536a6a5163655251f3604d2402312eef000000000003ab656a6e66b6030000000002515100000000", "51", 1, -1236976392, "d69c94c9e73174e4af2c3000e6da3781a48373f646a9b14eba1aa2478f11a845"], + ["31bc3505038ea5bf4e5730dc02514274f47d2e41054f51618e8fac4f255b13f2c6b2395de70000000000ffffffff7dc3145851294956d9a6de0986e7c8bf4eb34c69fa9ac1c94444f06e283231ef0100000006535352636a6a26c4857b1bbb619e85ad34db898628043d7ec18db4239b8a78087acdae971ba9a524a8d100000000086352630052ac63006f196b43021527e303000000000751535351abac6a4b38cb0100000000015200000000", "5200", 1, 1206849647, "014157f3ebc2f7be4eb3e531e1c8b287e0e2c9fc116523275f1516f652c6387a"], + ["ceb24c4704199998db2d11a85634588234b4780749bd26dbda704d267d315ce1055703d56402000000090052000052abab5153ffffffff0fa970991c63fb965c562defae44ae01ab480d05ba9cf997658a079c2cdd06f90000000002ac51ffffffff3b2f25380b43883162d9e131f0eb9ee0f47be1a5163784e35dc542a4d4cc929c0100000002acacf71089028955ee234e8556e5a881d79c9935893047a81873566a2e002a58e058e5a7c62900000000026a51ffffffff03a9dc840100000000045353ac65f1433802000000000453526aabf7edb5020000000005ac00acab5200000000", "006a6365", 0, 1647230717, "36ccacc78a0e469987089b8b3638ba71ec9ceaa69bfa8daa3e64cd17ac46da49"], + ["62c6299c034f0987c316c266b36d418703d1b22b5c90e98c429ef0bc010f0832063075a34b02000000085152650051abab634c44d36a887db972976cc781c1ee9f8bf0eae362cac3dbb5c02122e5e22f519e8ce79bb80300000002516a77243339deb65b443a6a52f7dd13f6cb7fc740434e683e4a413692ac6bdc01067a0885dc020000000853ab63ac00ab00513acf7ae10438ddf30400000000076352526a6a51ab4e3983000000000009535365ab5351abacac114d1d020000000008acac635152535163b99f2f040000000006acab635352ac3b56b816", "6a635153ab00", 0, 1171897848, "c3f6ce039981aed4cd37f652f896d67e1ce4ffbfd90d419fdf00e6c1a2543b8a"], + ["c7469d9404631c3ee9da01d735b58a09799e785d0a53e15446cf23391cc9f2d838e76cc9870000000000ffffffff48b3d15b82ab337a9066087957f319090dab25bd302ef250b1267a875484b59b010000000060fae4496ec2a48d6382367df13c273f9bf74b28a3a5d1f75c729d46f94059e4cbd836ac02000000025363ffffffff4c3dc2d12006abb2024337b8482d6bfbc7dc98664aea4e307d91ede50b46760302000000056352525265ffffffff0243d296030000000004ab65526aedb72701000000000553ab6a53abb4948357", "0063", 2, -339095221, "6d3c0bdc3b9d2ab2023e624377cc1dd01f298e2729bd58dc717a5ad6b237b996"], + ["f1ca663a01b32494095bb9e1395470ba11f01ad3c87458450132f55604677ccc1a7e7b77ac00000000066a0052656aabffffffff03c0981901000000000451656552fa606803000000000251ab58a6ff0200000000007c7fc452", "00ab6a63650063acab", 0, -1336646841, "5e8c36b1db2d31f8289ccb1ad1219e135788cca5948c02aabc5823a4b9282831"], + ["fd67336804afcdae6676a7917a9c3b95592f049f7e79b96a91912432c55f57c2780e37418802000000086553ab53005253abcf5399a7e4c44a78ecdde8aef39fdbb220ab857c64126340de1f102992f0423efc1283150200000000d2c26563e4610de0dc5983035c64710074f006927515fa360c1e31aacc6bd48e5702f9000000000000c48f2619aff4af53f7d02b51f42c4695b7a2e7bb8f81972c264f4a42ba3c9a9eaeb5a8a702000000076a5363526aab51ffffffff030be72a0100000000035165ab25cfa00000000000066aac5351abab019eda01000000000353636300000000", "6a5363ac65", 2, -256132103, "59951330f87a87322d841976c2b319ec892c5b719f56184349ec621be8788fa4"], + ["1d4129e404976a69c60eb9aebc7fee2f8780c25b2e50318923328bfe1c5a6c48d528426ab8030000000153ffffffff3c90468cec2ac304f7b280f0e2ac32cd1722419e198120866e6ad3d3f1c6f25a0100000002006a27e4beeeeb64992a142befa5a673651bd4c0701b3560c555171c25186f253983fbc5b6300200000003006a655fe79a5cfd0e4d1ff8d170d6137b13ba2df9afc00ba943a4aa5b35e404ff19922ec3a88701000000096a516a53ab52ab00acffffffff035bbcbd0300000000036a6500d4adfa010000000003ac006340f03903000000000000000000", "656a52ab53", 1, 447084901, "298a7a49d6da8339b4cae6e8ef6037fe48c8529697f743261d0b81a9ab36e945"], + ["3468ffb704292bcf48f6e19c42756e6aad4d267afacab219fddbf9bbd5ee5ade787fcb5d4f0000000009526300536352ab516a032f52385f4638edbb94d681b2994be21107377b07b893ec9dfd3bb24f49d51ccd1e1477020000000500525300abffffffffd631fba66163c67933c5275283a15901a4e577ddbd195f8c2545d62b462a241402000000085151655165abab529821168136d0de01317575015cb83b27d87f9080d4980a2e492d08b9e2bdc7134f52a9120100000000a32908b004599e6c0100000000009b97dd040000000008acac5352656353002e893f040000000005516a536352fb041b05000000000965655165ac65ab6351d7caf5ea", "5200acabac52656a", 0, -557179571, "adce5921966d32e2c9c959c2b5c039fa976ab8b8aa63be402b0c691cae1cf47d"], + ["71608107046808d8f5cbcb05bf128aaf336a11699eaa4df9f9004f36ab6a4d25da72b830fe0200000003650063f859dca6456f2f89a43bee38dfd8d6345cfeddf53461257368c91252f79b6db4e820048e0000000000ffffffff8f0ca8922e2f98fdfa68e83f23c97b8f7bcdf9a1359de5c12fc033fcf535f4d50200000000c7688a3aded1b520ba248b3e0542dd6cc055a8dbf73c26417a690be9f26fbd819cbb61410200000003ac6a002177ce85037c8c2c03000000000553ac51ab534c7267020000000009abacab65ab00ab515394dab7000000000007006aac6565ac6300000000", "5151656551656a", 1, -1642157580, "e5459c3045a78be43d5ebe1edd4934508bc9c38d3f1548d7fe3a5cb24e6729a1"], + ["13c6416d030030c455e8f292110bfd7a28494c61967d9dd0e3cc59e379f9f1b391a2087f2a0200000006526353ac63abffffffffded09cf87c7126240fb02fa1bc51695aca543b320c54a16a2a6fdf4ee0db25ab02000000026a63ffffffff4aa8e72f607609b80b796eba0316acb76bba744227f6368861c08585bcea49c80000000006ac00ac000052b8061d7603697e2f030000000003ac6aab3c6f56040000000008abab6aacab006353c424840100000000036353ab719d4c9b", "ac6353", 0, -1837289219, "3bfeeb55ef26656f3fe989773ccc033b67a25d48f31a80ba27afcda0c13dd355"], + ["00872330026769cc664a2ee6873a3ec66c40ab56820f54d5b65694cfc368208bd20812c9e9030000000563005200abffffffffc84bede66d2bb625188524337bd449edfce99f973fc049b541dee7b985b672c00100000001ab0010b93201ac057504000000000000000000", "6363ac", 1, -136503833, "bf4aecbd6c9c81b0e358a520ab71c368c99d8940a43d8d2b11b8dd2539ca47eb"], + ["3d90ca32025d713554729df44ff55f3e867e3f6e15008dd4587ee502469602b2a111d1a7480300000009005165535153ac0000c1e3511c577d10cf08b1fc58ec28b66a819da9b8c1824f5d5a2edc48ccbe5f640ffdc6d9020000000263519e2ee67e03e46d5100000000000851536a6552ababace65358000000000004655153514342db030000000001ab00000000", "536a6552515165ab51", 1, 237589208, "090719766dae5afc6c0043e592f69ae04d373bcb1fddced875a03a2ad73c055e"], + ["303f2a14041d47ed2fe49d8502e493f8a573c2b8119f8754ef16203b0256cfac2e8773a1c7000000000653ab5200acabffffffff0dddd12b3f15e42a7999d5ee76b46555dfd5047808bdb2656711ec107357743700000000095165abac53ac6a6aacf08d1363dfb8dcc64e9f078387795e5469658e6f3aa868911cd4dd8546bf1eecc0fd96a9000000000752ab6a65516352ffffffff9e4cffbd25d7144baa264ee0a9b995b4303d99a61d7e134469b64d027f160fa20300000008526aab53ab006a53ffffffff013e08ab010000000001535a844dc9", "52abac635353", 1, 1747033941, "096f6a4a99609a40a6b5eac169489d2c12c1be6bccf9c953224a6b81c8097691"], + ["82d943b20437953f9b6d9079ea9e764fd1b203cef98bbb546a51be57a494f48c9ddad936110000000009536a63650063536aac5e9ba77430d281ba2fba6b04b42c84d6dfd4bc9bddf2bb57bbd0ee39eb04cec3f51ac2350000000003ab5352fffffffffadac459938b189d52ce8cb721c04eadf8b230d11df93b366e2dda8d5df427ab000000000653ac6a655353ffffffffca91b8d899153d47a79dd151c725b8485f6f721661c45156f24291cfc41864e70100000009ab6500005153515163ffffffff04e521d8000000000007ac6363636500519aaf52030000000001ab44c4630200000000096a65516553acac516a4e3c7601000000000263ac7975cf12", "6551", 3, 971690063, "271ab5ec6c0c3958a5694bfcc6d076e1bf291797a93097dcf34771b4d6b74d8f"], + ["d5840da50417eb46180b7a3f9f33cacf06701ca65e74ca49b0221158fdc5a8bee0a4dc8ba2030000000253005b9462d5139ecf34b39bb51adc5e67532db4aaa90df1fb82d91aac518eec524393984a890200000000ffffffffeb288a87e63a54f208f7ae913f9d117161f537dfd0337fd0d0d89b4fcda07acc010000000751516551656a00ffffffffd3666ce80a286ab1feb1eeeaf4a4440ff4028159963857d54c4d182985fa1a980100000008656a536565ab656af8821309034ede39000000000001008edd93020000000005ab63535163d3a1c6040000000006636a0052acac5705ebbb", "5100006353006a6a65", 3, -610563223, "cd5369ccdd3ef238d359ad2684838e67fe21e5f1777221a8ad42ca9f36e4dd71"], + ["63f9e52c04dd406efc89a5a83a307df04c07c124c50121f64f49aa35ba5ea2168ebad41649000000000253ab3b9d91c6dc35d7f8871356f14521b07e6e947b6486b062c8939b82f898bfa048d942d9480000000006ab6aac6a5365e83d2f25708788ddc0bf576c46caf87049875fca72dc5b5c2750461433fa8d1f2dda3cfd02000000025353a6bbd5991947774e72e49ac8bb4429a393dec50a041dfc01f1383c90b99b438a5033f4d100000000000e0fab9902362baa00000000000252ac87d59705000000000663ab6352abace9f2f0f0", "ab", 1, -1913533225, "5762f941c2cc4dedbf4bc64cbf9b7942954156a28fab771f1dc009098d45b0af"], + ["ea19d3400185cef98ac952121ff4dacf73c802b94de7b66db8929c630c75fe5994dbfd14aa000000000800ac636553ab656affffffff025f270f03000000000002268605000000000765ac6352526a6500000000", "6a6353636a6aacac", 0, -1777736877, "015b56ed410ac7a24eb497a31969b6fa5911c7a42273e4f176b9c2d7a6d0ff4f"], + ["ac3ebfda0303c8abbfcf755bec9996f6c3bf8d78f29c9842780484cfa59d614fd7797e1573020000000452ab5265ffffffff00c94640d1d8c4c2dac4d2b2c513c86e82a28ae1f95ba4fb2b6079c640bd7e680100000000d9d5b5dfaba3ac588b2704a01dd74a0fade08c0aa47e6459028267db786bed2d24850b6e03000000050051656aacffffffff03e441dd050000000001656f4578010000000006ab51ac6565537825c100000000000000000000", "65ab53", 2, 1992078156, "ea974c4ef0ad9ae108fca8768ac3bf22673289fb985e15b19f6f5e00f18f3f8c"], + ["7e5976e90219a6e4ea066a5727c3666fc43efe3bc56e9700c92eb62bd7afb817c7b2fde59c00000000086a63ac6a5200526aa79bd5bed822a59f4651a400ca66743253cfad3b4e42640abc5d74a0d7039f4331da0264010000000453ac5353dfcef3880230eddb02000000000252abf6424e040000000001ab00000000", "acab", 1, -1389614906, "6944a55e540af7f042af9f1410a2fa237ea0ffc238a2e4454b677d302cd9d5ee"], + ["b03d938a03a27719b28cd58272a6216b9ce0f733c76e5f9cdc1823894e35b48cba4a5566cf0100000006abab635251acffffffff12a49b666237cdf6ff450866de3c0ef8681263e72daf805a0d18d262ec0a16840300000004ac51ab63ffffffff4ad0a86fab7011658d5c1b4fcc3d0a22f722697aefad38ec2393bf1ab1d00073010000000953abac51ab5253ab65ffffffff02141c91010000000006ac6a51abab009f9c6403000000000852ab53630065005100000000", "636aac006500", 1, 213055446, "d26b4fa69667b2ebd0dcf074e45b8f9efa7f0b4590eba1b7080d1cf51c5b4822"], + ["1aba890e03255dad6605f4f04a55a92c3dcf47e0a34c9c603bc70eb7e76ef6189c5e46fba8020000000300635399c61f72736e83172df93461c8e538d6aba873b6a9b6e5800b327b0c4455eb730cff0c23000000000565ab52656affffffff9a5c2521edf49bfb855099b88da05841caf11d93c98a39dae9c2bc34810f886200000000065365525265518cb3e233042b63cd01000000000900ac656a656a53acab6d821e0400000000056352abac51d6a08e020000000000137a3e040000000003ac5263879dacf7", "", 1, 472387961, "bfe491dabd95c4b1b712625003a7c092cab382319de28f07ed26990eedd3c6f4"], + ["f46692b701a8f5af9dc86be0350d7ced732fb41a951bb14d15cd48ec373a61ba114a6c8d71020000000652635251655383f447ec01b41f4a000000000002abac34debfe2", "536a6a6a65", 0, -499520554, "6c56d1a07446eb46a29b6ebcebe9fd2825a2656dbaed96d7d55d61c732018a83"], + ["45d6e78c0481a2e51a86c98a077f18d36e1a3416666533eaae513551979b99a5061b7469760000000008abab526a65ab52abffffffff657c4816cd9e7f72b8db9e7416b6fccde38a5e1cd4bf0a81fb8e2c35c07ed9f2030000000365636a4c00f98a7e61dc0027ebe87714c49b1cb7f8be5524634fa06ebf479149419d52b98ebaa9010000000900ac65ac00ac5151abffffffff04681778a12124766788382e7764b74e44278ad8c01d9516810ff3b3e79f1fbd02000000066a00ab525263ffffffff0398df67050000000003006a6ad1fa060500000000065263536a63639cc43c040000000002acab5bea26d5", "006a526552ab", 1, -1766128004, "13a371133bb676c4c8ae32949afe6881599c782697ef4dbecc2d2d6693f76fa5"], + ["bc976547025cda958eee7397baffddf4b5aac58cc923a81b6979c99ee10f7fceb7438ea4b001000000050051530052ffffffff870675d9675579289e8254621224d036cb536749dff88dd21dd7098ad7ff3c3a0200000002006a68af206603876a6c02000000000151a81da400000000000753abac5353ac6a63208d020000000008536a6a52655100ac5d45ff8b", "ab00", 1, -1925128863, "ac8bd77f8de0b900d511f8e4a489c2982f42bcae7f7145daf8d694f6063d5baa"], + ["126eb544023e4cc2bda49c0ef8acb0702bfd396e8a8392f5cddfe9ce94d47190ce23d90cf103000000016af348f66c8f5cdba8459a0c3f2d621c392b7be6a6a22e4b402a34d89ef0b12e128a669f960200000008ab515151ac5353acffffffff04307fee0500000000086363ac526aab635393c89c020000000006ac5152ac63519a2b3a020000000003656363925d28040000000009ac00abac656553535300000000", "", 1, -748153636, "cd90c7d5ce5c6ed15aa43455a7b5f0c69f1c7dae129c680d90e1d50b5163d7e4"], + ["a1bdc1b103b3009dae5844398b1b4c7d78a9cb8e71d8c002ec6a732c8c6ab477153b75ca33020000000700526a520053526ee5e246416ad3b38ad2094632568ebaa51b0387146e616909e0609d202f166c94fa04ee0100000003006500ffffffffa9d57ff682253dc5ee5f7690dbbca43d7d07d28f6ae6a72a05fc0caa5cf6a05100000000056a516aac53b11782890331bd9204000000000853ac63655151ab00fb7357010000000008535263005200656aa47f69010000000009656500535163535363231ea514", "63ab6500ab", 2, 638821850, "d112e9924908dfeec370bc6fd8ef18758a08501bfb07d80be57bae8e2df06cbb"], + ["aedc6922013b44d658cda59e6e5402d0c4e60c0dca9de4962a1f249ae3ccf0f2802e110e310300000001acffffffff0421f271020000000001ab160a0f0400000000045100520095add1000000000008ab6a525265636a00b86a830200000000056552636a6a00000000", "53656a5251", 0, 1344539233, "2dfebad20592712ba162bbecda3bc0623821fedc1a049206949200e1c0687d69"], + ["3e0d6d7503c5aa3e12a82223e0c155e694857084adbdc526d207b04df63b331ba63972890f0200000005ab65ab6a52ffffffff3130d0e3f9e0218c852283a1c6fd415c0c3e723cae2d582a47841f2ce9e8f7970300000008ac6a6a005165ababffffffffb6a704e9d4b6bdcd059442f795c245e9ff711f2c8e32ef62e0e400a1f5a0f35b0000000000ffffffff0162615d010000000008000053530063abac00000000", "6365ab63", 1, -314288178, "cd0d60f70261309b87280eb0b9f1e36abb57d4ef8d0a897744729ae260ac7ece"], + ["17ecc18a0256a5917348d3152b5a7e8fd879201b7ee859839f7a5ec5681a94b0ad36f7f9fd0100000007acac5263536365f402f8319ab475bb499519233304a019a4191adad8380abf73a32db49fab4e49214e2a4b02000000001326d59c027d49bd030000000007ab6300ac6a6353a4757102000000000000000000", "ab6a515100515200", 0, -966571152, "b0683e2161c69fcfb33ff7ce982fb907d705fc3eaad3e993b233518acd1fa581"], + ["205d2fbf01b850ec96ada220ea51e85c0b060b27e3e89a52645c32e15681de93d5b96e57060300000007ab535353ac536aa8b7f1de03d54d2c050000000005ab5153006a9fec350300000000085352ab52000000524e4eef04000000000900536a65ac51655165591e6624", "630051", 0, 1449481058, "82146aac5e3f3ec6a9f1d08f9a74f7d2a04d0c31782f8674771f2471268e9f01"], + ["c4b628aa042cfdd5214a1295c98dde088816f5d096b8b7a31d4a9e9bacb16e4f0c38e2b58e0200000005acab005300ffffffff1b6e3cad9bf91d868be29c2701afe04b37c7b183f7e886e7bee7764115351187000000000552acac5163ffffffff6eeac42f8cb982eece72649135f2861c76775066d1726d4770421d956a1cf52b00000000026552c3479817a4f70d6e988310126f4265b22374507a47d7a08c313bef70b7633144daa0818b0000000007526a53ab635363312985370183b7b20200000000036a6a5100000000", "63636aab006a", 3, 1887264852, "4dca7fabc229bef09522b219cce4520f04bf02d070bd53f903dc77fa3cb4eb04"], + ["70f2c34d026dbf9c6ae8ced8cb194b3e9d571cc9a7fd720dea6f7b09d7140ccfd8a4ce38ee03000000095353636352ab526563f66576a0559b421f943795d315b28905b8c3c8c773a10186e348bff48c3d413cc46645300200000006ab0063005353ffffffff0362b0f601000000000500ac0063007fd0470300000000066565536aab005afbea00000000000663ac5153ac51f15aa5e1", "5352", 1, -684460418, "a3a782b80c595b2441469f0df262cebc6d5da82e0aad7f1891f349bd429ddbc9"], + ["1e3f776904745063ac5579b280a52196aad56ddefb1c793158734db500dc2aaaf5b2228216020000000300ac53f6c213eb95dd8ca2ba11651a38870b7d0c7f3b0455fbad45876184c798255d51ef7eb3f80000000000ffffffff8a6462fa041746d7b325709896ea1b90a20a3af98c2ff022b935551e26ff86c8020000000400636553ffffffff25eebb7195577c7f5d621f2901f69e12ae886fb892719ec197946089086c12970000000000c0e4ed0b01cca77b05000000000551ab65535100000000", "5351", 3, 405663304, "78e2b9b916ee2f34c59234d7822061daf021e057ddc70fb31db5601b842f4514"], + ["7fa212b90358a4ef704fd858245b897f0ae8b571c8b9d6f955d0ef8c7af40c173a2a77a08f0300000008ab6a6aab5165520069749fb68acbd925804b5dc8b3f864b91c217b90a9076e0c4db71cf41c10f899f893caf30200000007525251ababac00ffffffff6ab6e135253414b9041f4b1eef3ac2b1e0f94c4b5093b5c74ed2a01981b95e4a010000000152b930538d0137c4e803000000000353520000000000", "6565abab0053536a", 2, -1952180622, "9769fce4456bc70211d4c6eca9336e012f9143d43ed663cadd1fbc6c494d8f52"], + ["0f4eb8ed01fc4a4d924b7bb3eec0b7422f0d2fc860a26dee5ad8bcc4a3f00c194c60c68a9a01000000046551636affffffff0298216004000000000763656aac65656a172127030000000005515352656300000000", "6a5265", 0, -1417614251, "e9fd9c90382490911711a8676815a50e252821daf1c8f987c2fdc3e1ef7b476b"], + ["72bb9b7f045bde36600fa576c47f4096d96d1d17043a3c29674657b91a897c760a55d075c40300000001acffffffffad4cd5a76167f0e51b7f8fb4e4ffed99719855ad7bd2888fcf612b687862f30801000000056352abab6affffffff2b47c4640cd9e18119144b4729484d42e7aa796a4c2b421d7103d741b56ffd5a020000000453526500e9ca359a1744aa9758996d68cad5e815862dfd3cf6d643de1fbae603af4fe735ff4cd7820000000008ac5351536a510063ffffffff041adad20100000000090053ab6553ab526a518538c0050000000005630051ac514016db0100000000046a656553654c4a03000000000000000000", "5252ab", 0, 1897369539, "62eb1b2cd2e92ba6a05315f9f7d23fb9a4aa0427f87f7b6e3ca862d4c55bbf18"], + ["365b016e01b12d5f5412bc50c741184fd507b330960129545ba377e0a389b2f7b44c8df4360100000003ac6352d4c238d302ea73fc04000000000965655253006365536a5281e6030000000009526a6a516a63ac636556b14cf0", "52ab5300ac", 0, 1756041327, "d6e7256a7e3c6b7ac27907ea7515f1495bb35de20e386c7811d5b03ca77a0882"], + ["315c6540041a6fc276c73f94320e1cdc72ae7d54bcb917e4bf28abc3fe57bb5bb39ceabea00200000006acac526365ac6be7e2dc48f34a7147d644e8a0e889934abfecd52af844e956b297a998755ef8b693adda0200000005acac655253ffffffffbeb54cec55f1451d4a7f8e358c1e81072aff445964d28f64af34f0a09c204d4f01000000016affffffff671778fe53dbe1e1dd72ee78f5f0075fb3853e090bb52dd5c9f31299794f1d360000000005ab00ab6a53ffffffff0240edee0200000000015357ea23030000000008ab5253ab6a5352ac465fc222", "00516a6353", 3, 1550454496, "3670953ae28f67e0abe03893be715ba2d734cb81198a3d3f61d4f5581447ad31"], + ["4bee3fad02f98aec4d50dafe1142f157ccc9cc7ba76d791df4d5be33c7b06978f0d7645261030000000163ffffffff82b9a0eba0b0878e8cf8acbcdecb48a0ca5f1a1282cfa7d963a3f93222d41e050300000006ab6500ababacffffffff046a56f0050000000006636a63000065c08f630200000000025163c349180100000000066a52516a0063b275f6040000000006ac005151515100000000", "516551516a51ac65", 1, 1533747403, "1e541c496cb037c66d6bec8b60c7ecacc927b5f515fdcc75079b2f7175e69938"], + ["a3b8e01a04f62b919e5bd6c94ab82c8e0c409c9e6811e216528d90d7018e507eea4a0f80170100000006635152ac5165ffffffff104996729d1e679e06c7b224b0686e7f3e1e96eb72ff18279033be083ec31bbb0100000001630bda2dbb00594191e8d78b59100850c826bf1eabfea19e11f605b6e2bea92c6c393ce84401000000056a635100517e6905e2dd6e98312eeeca980330fbbca8473db888783c1943f35e7066bf607b09f0321a030000000100ffffffff034d8f350200000000095252006363acab51ac27b96c030000000003ab515105d8c405000000000552006351ac00000000", "6a", 3, -142253211, "e0f25adbadf00a2207b951155b22b709f9a0f26c6bba62d317be14482367c598"], + ["b0f6a31a036e896623f0afc839b16b1d6de9e6b12876961dd2fb47a7aa9e156ca1a393ba2f010000000151ffffffffa03d55e34ccfeb66e8c273f4bfd01b6fb1c55732a17c4c124e16bdef1e79e6d502000000046552acacc72d8574fe64565f8c710c87726508c8c110c718fbdb815964a1e5a63de67a40d22184c30300000000ea9ae76d02c7f4d70100000000045263ab63b5b77901000000000665ac51abab5200000000", "6aac00000065ab", 1, 1292068694, "d275ef9597a0aa0ea2d9117016c9d1d154b00dc1d6709696afe8eab8dbeb6304"], + ["9384bad40214ab1a4870fab4b33e307389dbdeafe5d03ab7a485ce8204c75fb73b1e71c2f40200000003ab0063c2e0a3c3d1399908079525fb6af8ba51782a4a8ba6a4f7164065c0e6ed0a00c168c1c35c0000000005ac52abac53dc17fc37039abfda0400000000056aac000000c8c0a10100000000075263ac65ab65acf4fcbd0100000000040000656300000000", "abab", 0, -1763928874, "5ba4a75acb1d892809319a0509be3ffdb594380477b12e8e67c43ab8203bcc24"], + ["24f7042b040b49bafabe7bf286e15e7280fb587f320d9f70d665d72eed283d2d9bbe512567010000000151ffffffffb79a2cc3d863a552ebb329966a862072b23b9e22821867df1c0b3b2deaa235280000000007ab00656565abab483b5ab52b5ebb44eded8d0d0002d4f01a9c48ce9c5ab2a65dfa29cb55dc38189ef3fa4c0000000003ab53652155835373952d7e7f62506ef389b8bc0115b6f00995fe6f9837284f55fc4bb9d9e15e000300000004ab636551ffffffff029b2d4d010000000000180ec00200000000036a53ab00000000", "ac00536aac52ab5253", 2, 1784168817, "6d1b4938b38d7b1a4e07b9af2f19f9c0ef971cd8ef456c247ff278ea580ea598"], + ["d789c1180466be0f01474b8bbe03b0490aabd5cc478c582d01239eba1fa1a367d6a74459050000000008ab536a52acab00ac4e5d1579d7ef43850ae48686a77ac5ef87229b0a9c677cc7af56e4e9b387fb617b040686000000000029c75b675f60e8e0342e8850ed6e6c778f6779af94c22f87b54ef1055f1ce02af9146525020000000652ac6a63ac510912a4b564bb45ea923b01894fa9701e5720a90ddc33a14d3e1f740ea795f86ce9cf65d30000000000ffffffff027eb0d201000000000653ac51006563edd5b205000000000151b49c4593", "", 0, -132062515, "b71cbc3b47fae4f54137a50a699c94ad0b85f222770019f13cff383cd7251a82"], + ["da03dd5303b7e5f4df596ee61f4b5d1155373d20572a6c2b17ee3bb8244edcd916e5594524030000000300526329ffb8db561536e2a7d9bc431d45e7f2f10c0d3696f840c612ef635a1a7ba3ca29d48b450100000007006a516a63ac6a399bd11b147e3baaf78dc685aef949e650618305ef83690c635d891990bab607aab752e80000000006636365ab6352ffffffff01c5b402000000000000838a3e3a", "525300006a", 1, -1298920583, "7092de3956d913537eb92c4c3b7d9a9269c09e0a1e3b8609eb0c71b805139498"], + ["c4a1a47403f5d11ae5880bb5f8941fc1a62f583120d4756e3b4ca3e6fab370d1f0da76fc1401000000046aacab52ffffffffb72c938d0f6bbed792707e4ea085aac40d2068e6444e9950f54b261e054caca9000000000552acab636affffffff4ad30374372d99e12cb2099a251793ee3f621cf72bcb97eb411b3dcacf3c8d420000000002ac6a43022673044fb21b020000000007ac006352ab65acb567e0000000000009636552ab5251635153adf85202000000000153aeb056050000000003ab655300000000", "6aab00", 2, -307813384, "e9f5726f1f5b284006843e74667846af38d5d393e1b4ebaf087232adbcfde884"], + ["6d49df1e03d70a9d0c531d1e4488d51a2be1b940c72fbf46936205b386afcc5e7d41f88e48030000000865655165acab0065ffffffff5690aff289a0355193368c32ac513d8ac522a996e0529279cc4297a08235f59a0100000003ac65abffffffff0bd57ccd8d99f5a9f5cf84421fba7a1e20706245f76d4b103e7cedf4e7fe0c04010000000153a33aa98b03e263b6050000000006ab6a5151525368a4f505000000000751ac51636a6a651446c001000000000251ac240b30bf", "", 0, 1241535427, "bc8a2efd796d081c4568dfca91d817677cf4882b1cd5bb0800980eff4101e706"], + ["a6ccf85f04aa4117f0813b214ec511698d3d01ffea7c0aff480dbed3bd7e1cf1d4a184de850200000004006353ac2c49dba62a5b26814f5ec8c2f59a76ceccc274d02c83b3db446469908025b50b46306d050100000009ab6a6a536a51516553a1e01f53b90a46f4703a8047ba3839380d45e36f6cc3357100b9d6b99850e95752540dbb0300000009ab00005151656aababffffffff4012092680a77b9e31b78eda58f8155105331e02a04908812f0b9f1cf585699c01000000065152abac65ab8d24a862015936c60000000000056a6a52516300000000", "5352ac65", 0, 1426666310, "9fc01cbaeb367c84f306db36e2bf29a05b5773bc139dcfd2ef9dc4454eac5172"], + ["85ede8ea014b2aa1e839e259010dd84be915cd075a2f84ca086d4417b20fff0286d9a0e08a0000000006ab006aacac521c729dcd01caebd304000000000663ac53006a5100000000", "51ab", 0, -473546416, "91acb50ca04888c1c5408fb2aad310d2558573e1e0e9e843e7a64edcf1a5a0f0"], + ["374ad16904915bb9e536c1a0b8215f5c825c8b28eae490b659120256dec4913d52d5cc1c1b01000000076a6aac6a63ababffffffff5126f87a97f814ef389c0058609e285148c9e4f4fe444013c19304bced6979330200000000ffffffffc91d1d2048590284454d0ffd7dc8b622d26c705d593a2d8eaa5ca4826e615b5f0100000007ab00ab5100ac638f807f11ccab7cfd3b0c291ba08a38479c9d6abbc96e688d7761344bcae8c8269db03cf80100000000ffffffff0358681c05000000000963acabab63abab656509d4c40500000000025152670fa20400000000045352535100000000", "ab6a63536a", 3, 736517463, "1cab32b4276f5b4de44d5dfe57babf9303e11604015f0e0338bc677af1985482"], + ["2d898f78044b3e9346fac149ba7026fa43fb4f87593d28fc32204be7968cbbc2c7704e749002000000096a53ac6500ac515363fffffffff037a8c57e6bb40ca052f9315d6b93f7df16e083e6468f51d06b298b7652152a00000000025165ffffffff8700a1a3362d775bcb964713468acfba3d9d29fb3c9186fea9f4dcc25e5cfa180300000002005240124f1f1f0a5d825469570bfda784a180e8cc56a1a9a02727e9f526250c31b475c63e3a020000000665536551656affffffff03185de7030000000008630052ab52ab6553fa824b05000000000061bc700000000000056351ab6a0000000000", "ac536365ac", 3, 848364529, "897bc09a6e29b5ea4b42e2959bc1df15a7b09f52fcb42105c3ad18c4b3d1eb80"], + ["c1fd30a30311af0d628dd3aec050332a14b779ee5c83e76b3eb640d10abe4355c3a5f45b110000000004ab005152ffffffff77b0f905399c95ff7b497192640c649873aebc09783920563df05419888537200200000007635251ac5252acffffffff7803e30c8b9382cb71b701a9138d47c7faa6925a6e6d6a7db293f27b65bc12ed010000000163ffffffff0488c50105000000000651ac5251636a06954103000000000553ab006a53707ba005000000000165c5935a00000000000253ac085ac0fa", "", 2, 302042195, "1bc90ef557a45f9c77756b4d5c44221bdb3b50629a3aa909393273bca7c7cb52"], + ["ec1d78f202276029e2cee46b7781e62784b6961a81ad67401f2fbe3b264a3f1c74d41390a10100000004516a52acffffffff9ebfffcb9b2accf2045bce667fcdc55f837f3399f875d5b6f854d427cd7a039d0100000007ab5163526a51531ce104b2033cf7d802000000000251650d489f04000000000700520052526a515442de020000000001ac00000000", "6552", 1, -1622174594, "4e80b8013e418b36a8e0fba73b53726d2307703f2c6cdcc533c2b28c4479fa3c"], + ["5c7710dc01f2be3d3b6551a4b98362086cfb4e01e67c417183c696217b4cfd9816dbea9ad103000000086aabab65636a6a6affffffff03aee7be03000000000078bf6100000000000551536a6565f546430000000000045352515316abffa1", "53006a", 0, 1383914842, "6ad64fb8d5ff57901852c380b23b172df88ed9e6a41112733e1a5593ddf7def7"], + ["413b24e10150b52d3f59c044b267f4768c53f6082b989a5b0684dcf8fa1f13bf612319879900000000035163515bf32e8302cd81d00400000000000254860400000000045151ab63aa209171", "00ab", 0, -4689462, "14ad7a1f09befd820e8697f94329d6ddd5dd9024999915e535d91db96df2a5cf"], + ["3006d94c044d7eaf7f88b0e6527bb4758a6c1261b7473c1abd348ab51b976132c44d8f4a920000000004ab6a6a533fd14394d9d82c921a5244222621651e9c904f730c559bed0fcb927a66c2d14489df7fdc0300000006ac006352ab00ffffffffc6c67b3244d9e6dba03dd43f82056a2c0fc1b4f00a1cf0152ce517bf41f920ac00000000086351536aabab656affffffffa42b224fda5160fea169405c7a3a2105f5acc5cc04274b1b4e204c02f805262002000000065253ab6a65abffffffff0247ddbb03000000000763ab5152ac52008ab934030000000009ac6352636365ac635200000000", "6500ac63ab5300ab", 2, -1956570158, "8ec92d3c1d987d1d6c09e4c00306070c57e534c822b8d0deb787159a3dd0d64a"], + ["11d7780a049f8a04e5b333956dabc29f943e95e4e332593a7ddd0a469aa57f49d5f7e6b562020000000565acac6aabffffffff8d08dd2e8c8d70e8837eaa7bd346a50b172e0744d3bbc8097e0e0af77eaf27bd0200000004ab6a5153fffffffff78524c39f2ef725ea41cdd438df8e118457fec13a615aa6140f7cd9b44db01901000000076351516a536a53ffffffff1860f60d7fd8841071c9260d29443bf4fc0b37a0873ae719fbf63150bc38f090000000000900000065526a630053ffffffff02d8007a040000000003ab53635544ee0100000000095363abab5365ac536300000000", "ab5263", 0, 2113876971, "9395cf230521d903c98d4b4cda0de92f941bb77d0e127b1a4fdd627382d79fab"], + ["4f19c5e0043d1d018a298eeecb20e0fc5aec769362cab0fa11d602b58090bfbbbe81a6a2d70200000005516300516564145c3db42c676adacdf081de4e16f4c16c42eabc18e80f414e4cd2229db84bf7a7152401000000096551ab51536a6a5253ffffffff02c71305c8a38a0941a7a8fbc747e74f4ac79e7b58fcd8bd7f94bed3441e296e0100000005516a526aac048f6b4f02f3c549027fe6793b52072aae7f8fa2e62c02b68363891fda4174735a7df0a50300000009655351abab5365ac51ffffffff02638130050000000001ab9cda1504000000000000000000", "516a52", 0, 863756878, "427cb2013dd45dfc6fca6eb2d0e2961cd0e894cd66d7a35cffe005ba8fa6526b"], + ["c14e9b1c025d1d68d58e7aaf6c1ec39ed4c3518014f959db6a57b4902e60b1da7c3a8978830200000005ab63526a6a417768ba5d4e416e3d4736d0b99ef932473127899b31110c69c2c3e3ec045cdebeab439503000000025100edc373f10208d3a502000000000563ac635253b3dd9e030000000001ab00000000", "52526353ac", 1, -2061206669, "b728e63f635b4edaa116a8b2e67e8a8c9b30b16e02e8544f163797f1394a0c6c"], + ["fd7c80ed01c8832320166d47a40d5f73882c38e73fda1fc0c910c8de6da184ac3833bea909030000000453abab53936fb03403a1042205000000000963ac51515151510052774e850200000000095152ac006aab525100aec517010000000003ab5200638e0f83", "6551ab6a5353", 0, 1781978731, "f85017c90b4f47615fc488eafb6c2a4fe23e0f6a5b7f2c133b894bf3254fe621"], + ["a64de65e033e5ca06c5265d2740e15a14fcea1d47f37fb1ac8c0bc968b049e586607713ef602000000085153ac655363ab63ffffffffeb78540859727fb8d7d239715d704e47f07d2c6ffd8d9e06e0ef706f646f32d70300000001acffffffffeaa5fe9b64ec2db8fd43c97c47efc8168d3ce25ecd951a20c3ab8a7a7a909f870000000008abab63ac53530052ffffffff04a9639705000000000353ab63a3535d010000000003ab52ac18aa340100000000086a636a65535152ac9a5361000000000008535365ab655253ab70aaaee0", "656552", 2, -142812169, "2e64c22acf145ef186e1a1f01cdb441e126c80d3186a9ce5425da7c23c73bb48"], + ["81d055b403d0efd626abecd436f529ffd4b4e91bccbc809bc5aacff1446d10ec4bda5bfb8a0100000008ac5365ab65656aabffffffffdd017e72185919b5195b9be2cb0d3a306f365525420bcc885e9f52b5d16bf7160100000006ac52636a52ac772727ce53e0073dab5aed4a4d8512191196fc039f214fd6f84e4d7c9cf0ac21456e8c31030000000852acabab65536300ffffffff035510b2020000000000309f160400000000075152530053525392f1b803000000000852ab0053636300ac00000000", "656552ab51", 2, 28401615, "7b5dd17799c5c1c586b6dd641ca12652fd358fac997d83267294fd94dfc7f912"], + ["034d05c302013b2b671eb7146a546d70e5442f98f773d000eb0b880a74877d1264ad87dea4010000000453acac528f0a9a676f712e5b251da51ca7967cd73c2008a874456be3be2318b73366226b27b98aeb0000000000ffffffff0314bdd3040000000001536c5ba203000000000951ab635363526551534f8c2c0400000000026a6500000000", "6553655100636a", 0, -119278094, "642e458ed722ae400a4c0638b9bb6b2daadd8a897d57be6200bda1a88ffdd0b5"], + ["d4e0c999035a81f8faaddc9e4c1c40bd4483c12d70c5855ef85115e9df8779189a1f20040b020000000652ac63ab5351ffffffff7389b4dc8382ffbd090c84c819a3ac78ba13e4e06e14038f1fc987d6305bd5bd000000000351ab53ffffffffc569ea340c029dadd9d51a32016941b39c41c66af99883deb25a7f2f0f6cb1120300000003abababffffffff02c8d6ce03000000000752ac635253656af441e503000000000463655265fce25580", "536365ab51635165", 1, -301040188, "eba2d9f2218fe86d3fbc34b7c4354b86d0c25f0c06731c4487c9782c20cca10d"], + ["8170f7a70398e6f89d7a43efdbe602bc3f5e3ae6a884e4204f9f97e101b41667ab54d810350300000007526352656552ac9f3471fdbe082cae146d2a853586e5e3c05527b4786920075a734db6d81587d43f5bf57e0100000008ac6300ac6a516aacffffffff4f3d3b2229a61aea91df87c8788dd0db6d075d0e9ff00cef7b7c53ed262f7b900100000007636aabab006565ffffffff0299281801000000000665535100ab001af20c02000000000400536aabe03e9a3a", "0053535353", 1, -2051559963, "376d883f7e34da596a769e6b8c7b3535db6c879e2fb7e83c4f69a9f648461d25"], + ["b17fd621028b83d930bea6fcbdcc821b1dbb84b7e3ec5b50c1d29f5b79fc16b8f63ad7e5980100000008636353635265ac528aa129464f59c85a9352eb819f3f0475175d85535a07af610eebc78746b1742364c65bec02000000026365b02c6a84046b89d000000000000063d230040000000002abab83cc40000000000007006363abac6a63ec60340100000000016a35bbe7c6", "5263526a", 0, 1866394361, "1f38d8e2c48ce1e288cabdacb9f72c124bd5ce7fb68364b5fe536ef51a54a1b9"], + ["57b14f6804556e7bec2d19fa230e5a03fac3e58950909d89f6d1a8f7ae24dc9bd48233d3c20100000002ac00a446edb9237996cc746e493bbbfdae4cfbf05f051900daa1b9d8f5a5578320321d677b150200000007535365ac536552ffffffff1e684f4e2fd3312bcbbb801db44755629d1c1dc0445fff74cb9e99c09d5866ef0100000009acac65006a535365000052195fd38894a087ed0676b5da99133f1c5fbb68b96979af31119bd4b7603f28e702c20300000000cb20e621026b1064010000000007ac63ac52536365d78c8f030000000005ab63006500f656519a", "65acab65", 1, 140087288, "8665e5e603d679c4d74131e37a2d677d13632a2973978978931696c6889b3187"], + ["b859174903d72b8ceeb657ddbcaecb2887dba1fde40b7d4d1cea65ef2ddcea790d4dde05940300000008655163ac6a635100ffffffff0f090bc58d14314c8b3b5197a3c479f9ba5ffdacf49ddabec9abbdd1f0f974a3020000000951516a63006aab53acffffffffa4520cb69fe8449816700da1c1f0e584b70bcb588fc6521d0fae68caf75ae91d0000000006636a6a53ab53633175f7032ed77302000000000853ab6a656352536a2eae8c03000000000563ab6363658a31e8050000000005515352525100000000", "52ab53ac53ab655100", 0, -1162810883, "2629bff26f0bd38f2601a38a49405fdaff0eb1484b25cde3d23c1605e06044b0"], + ["3ed04aaf01572ffb8a49ffb168dd5bc1aee7539c4021499ca72c80a8f9a6a4ad8ae9647d290300000008656351ab00630063ffffffff03f40114030000000003516300234ba5040000000001abfd749604000000000089c51483", "ac51", 0, 1800071672, "18bddf866773d08703d58de001c7c7fa68bed8efd76f529d173ed6a6cd68bbb7"], + ["9b47e443035f5d36be51ac41627fe8667c35de62e8c596e3cce94695fc3ea0f2fabde23085010000000351006540db32318bb57d26a784651564d7e8d279afc9f5d597121342a765677c86c129db490ad000000000076353ac6a53006a7d47c5f3555df9da56bf4cf9e6acbd3c8d7948d49b0918ae80b1e2cc522c98dc72ce19990200000005acac526552a0944799014a14b9010000000005515252ac5300000000", "ac", 1, 497314034, "076737e38d4806215df63e733c095d8e5e6969de462ed815f5348e4e060a0738"], + ["2c8a166f0156d4cd4cfb9ac971256ceecb4d3e61ed89a2613426a4fe5d125a42cf8a49e3bb030000000465536aabffffffff01378df7010000000007635252516a0000b6b34174", "abab6553", 0, -422960684, "98b161268c2c59f3ceb31087d5dfc16aceab0eff7f2a9351e452c58d6542cda0"], + ["e0bba42504d7accd5491b979a2b66a7cad7ab80c3f923ceeddaa2fe3d3d021169c592e8a0401000000045153abab46900b4071d3cb63570b7a90b8c3b1b29a0c2e589eb04f15339d63ca2329e0d7d10e6af9030000000751636aac516365ffffffff5f85e2198ca30bd42fbbe548a1e8bbbd49b331fbc5eeb96d1ccd5f55579f620c0100000009abab00536a6551ab6a2ddea1091ca84500d8adb140f186c81c7e6afb65f0bc8d2425a3dbcf0cf47a723764656f020000000453acab65ffffffff0258352000000000000963000052ab52ac5253b0c313040000000007526352006aab63d454a783", "63ab5365abac", 3, -708359469, "b9e752b6e681fea9567801ea99febeb26e5d1f441205ee77d081035f3d1f596c"], + ["c2bf7dc60243003f267cd8c217594deeab45d3113c9bc80f38d99614f255b4c1a7d7af92aa0000000005ac00636365ffffffff0577a69924e56778ac8c561d4b28601bcd395ad40712935022f3530f95a675d90100000002ac65ffffffff03437f810100000000046563655228a3f40100000000096a5152ab00635252ac90fcd4020000000000a1fb803b", "6553ac53", 1, -198268937, "bd75bf2d63f54eb46bf73e2678382cf9e9af7cedaa85cb21b7efe793ff384151"], + ["8429cf9a04bb38a26c50f993c2e2ab4ccd7310579e75e900dc6730fb33a0ce2a11c282baf10300000003656551ffffffffd613d25a2f28590569912691413cb688edec019103f1da3de9a58301f360ee5f0200000005ab6563abac9a95fd585496c1df65b7b21f8b875a2bf7a0f8a5133050e4a21336a07dfeeff9b8a2b2ea0000000000ffffffff42d94fb62a002ec9e97e2fca1fe968e2fdb58dd96e3248d14ff8842539661b2f0000000008ac5251ac5200ac63fee36a0901e46dbe0400000000046563ab5238356541", "5252", 2, -512077079, "11445d7ff960b6065c536c9f1f50c7a0c03b8cf028681528e035eba015051cfe"], + ["c980fa2804c01407feb4b39b9f5012373e157e7fe34be3f4002fd39a0b54f6989bf6bec97e0300000001535e162132bd388669e0c63b50255095f65a922c4a305a5fc39d4d9a31862859c8107694090000000000bc9a76a285152166c4ac89683f4684e86df293701f732d05ad9916a117ef88ba9eff0ccb010000000086ccb827ad89d552a049c44807a003a5d1bc8d30b165793f7ff7d7d7d2a7f8f25e5c031c0100000008526551515253656aa07f233a0122a8af0000000000086563535263abac52f31f890c", "0051ab63535351", 3, 1442549578, "0dbd5b777beb864c5cb911ca72dbd6f0b23b51af20147c22593855f443a44bc3"], + ["1f7df56903c817b47204fac0797364391224260c2f6b83d742a684e33515fa8ab8f56e811e0200000007006353006a63ac13df6a64e1a9057ffc480f0345352e3af9c2995c52082dc33a907e6e69c4f4617a48546c0000000006abab52ab6363ffffffff13c8fb14e124cd02312f07df835fd36bced7059a270579ae05fb36d0a642b6880200000006000053516300ffffffff03848393050000000006ac5265abab53157aad02000000000900ac536553ab6a530043feca0300000000095253636a526aacab6a00000000", "00ac65006353ab5100", 0, 906188643, "fe3c2d93eea065e6545ce93c8b665794b9a6defd68fb22cb3f2debc989676700"], + ["d843a6810226c15b6100363a1b0d58bb52744626d2519486d4adb2ef8ca09abfdf41d209cb000000000465ab51abffffffffd1490240167b3eeb688b5450b8a8be7d158f55ce0873f2922329712837a53b610000000001ab0ff528f201c1e891040000000008abab00ab636500ac660f6329", "6563", 0, -1578678315, "ef033a099d9902a24a21c1d6518e476573218f730a9a754cd40dcbeaba12df45"], + ["f561fed701c66bd07da229e3684cd29d22a368ae91a150a884a2a971468e9c79c3082c0abe0000000007ac00515352ab65ffffffff013fdb54050000000009635352006a00ab65ac3d229d62", "630053ac006aacac6a", 0, -1899601802, "39baec1eb6a08078364e65c3277a012cacb7a4630cf5129bac7a5ec4ff86986e"], + ["200e562d02e6491276c71f0b4313d923c07c758a7c3b19524892ea0ad932cd50172c0a00a50000000007006365535300635e8197e3cd216a3b71a7a7b8c6accbceec3720672bd22ddfb18da29ecdf20f4d1fae716b0000000000ffffffff02620f0101000000000965ac655200635151ac762339030000000003536a6a00000000", "536a53516a51", 0, 1080771658, "13a04e189b22c86ba347a0fbbe85f09fd351074b009abcf851e38616848bb882"], + ["e5872c7d01b7c2d9831c04385b1990e2101d45068645f9a901c417258486613ce6dc5eac20030000000751005165ab6a65ffffffff01bff73605000000000763526aab51ac5200000000", "6a6351ac65ac5352", 0, 2020328318, "a6df26497b9f488c6b0b5123347df4945ee78eb9d1cef6c91ba9e30329798c4b"], + ["f4d26c800377ac1979c8b731af475b96b2263f11c75a09bc17055524684cc475979d871f6b010000000453536a510cd72f004cf7924cd5d0c616fbb5355d73f4732377f4f3a862d3652acf8b47665c54333f0000000001acd6f160d688f3455826a8725d1f17c123d46afe05879470d8c53a3b2f67847727c6be2ee40300000000a4531aa403c8fe43010000000004525251634f5b2c0500000000056552630063dea98b0100000000036352522acdd97c", "65ab52", 0, 1597648123, "c919b6478eda9a4fa099eea0cf4dc7f4209b53f268a11c79d3ccb183b0545d3d"], + ["b74c308b0383b6f04f7aa4d019ed6ec3f868b6690ca988a93b6a9767130b72973c3b35e12b02000000008a20a195cd34340a56ffe9819004595cbd1290f375eb480ad53464d955911134e0da1d780100000006abac52ab63acffffffff628bfa9df7ce8113cd67d231b36afe06facff1a0360410bd5fc7b7c8983f9fa20300000002abac33b8901002358e2d0100000000030053ac9bc1ef01000000000000000000", "", 0, 1085631610, "f35624b305ccc55f97de8264c3811ae3cac7aff42a55a39661b5d22639654374"], + ["d33c21e004ee81add749fda6a4a724e79f0dd2032025274e1baf3cdee272993295e89b01dd03000000016329f015cca8b668b101c07c868c600005658a44dafa2507fbf8478f65d6d833b1f0c5cbe30300000004ab6aab6afffffffff8ef1de4f7426c62544d8b01e584e257dccb781c5eac39aab881981be4cf491e030000000800acacab5251acabffffffffaa942df89fb397bcf581f0a677306de2a11db64f4a799f79f5ce28ea1231061d0200000006526a5251ac65ffffffff044eb8b501000000000151518035010000000008510063536500ab5143bc0c030000000004525253513bdbff030000000003ab6a5300000000", "6aab525365", 2, -1553918251, "b7ff235b26c09d280ca1469182573efddf0972a21ce203853d552b70d270f023"], + ["c754697b02cfb435d4d7e28d212eb2b68daffeda0b87acbefbbdf7dc5b1738b224f0676d85000000000952656aababacacac6a82d4a79e1b1ceab0de60ce23d17f2cf236641c8629fddcae771530f540937f4ed2b0ce990300000001ab468fc1ab0214219f0100000000009ba0770400000000016a661baf44", "ac526a", 1, -233982256, "62409852a7e8c3dc5444505dda690df84bfa9a48436799b0b34c2e1a26bb4ed1"], + ["5115c3cc02d1a72c91568bd575f2e5546e2a53fb22ad078b8cc3157da04102db0bc880684d0300000006536353525300b38101616f4d7c4505000a1001de2e3336c04f9adcf5a99d68e9e8790af139246ba6fc7d030000000863526353ab526aabffffffff02c0daef0200000000080051530051535363f3b424020000000009005351ac6a52636a6ac5645b7d", "6552ababac635300ab", 0, 2141409140, "11a02ec28f3e5c084bdf5681c0f10271470c060030760454427cc9b8ddfb5395"], + ["fc40e11803129d656cbd459495246048f3a4fde20f772949806ec35e6b3cecb28351481120000000000851656a0053636352fffffffffd4863fe1021cbdf9799d733931bab05eafcd6a607bb1c08f0ddfb294d27d2a70000000008ab5265ac536a5263a050c88edebe63570ac5ecec9e3d38083739f10e227f417ffd92d07184a6fbc2c13cb4c3000000000151ffffffff0177713f050000000001ab8db5f904", "ab0052", 1, 1962536284, "d6ddb67e4a1d1ca7be6510e75117134a8961e0af57cff2891f95207ef3411f54"], + ["9eae60bf02458e731dc4d58f24547d01bdb3436be3546cfda7cf24da3110ae798217b3361601000000025363acd6b7671f7485545d00612343a039d9df6f3e0ed4a22cf3bf785fc6e355d0064fbe91d70100000007ac525165acab65ffffffff01408edf040000000009516a63ab5251005165bb0fecaf", "650052acab5265", 1, -1744030777, "075a9a59afaa21d39c0abd4d6b0c63cf79101ba8df5949cad6dd22065ccbdbe9"], + ["e255018d012c72c74e3c4400e6698123e3c154c911459bb326573dbf7eb7fb2f1655c248900100000007536553ac515152eb540d5902d25d63010000000007656a6300006551a1bd6903000000000852ab5365006aab6a00000000", "52acab5263006a00", 0, 1779434869, "d686cdbe4893a5a8bcf79576fda7adf7b29f0d5049ddc86cde0a7d3e2a50bb3c"], + ["696b6576046becbec03c913e63e22af522ab539d3e20f44560288df1f8bac64d10c69f6dc700000000056aab65536a9f581cd1fa803a6324ce9e66caade46d80638ad5615757ee2d6cbc18c3d4672308b550ba000000000863000052635300001a8ea1cbb85109b9275b7d3938cc3bfa6fa6f40b8ccea710d827903b47a7be929370901e01000000086500525151636aac0fbcb94faaa34d7983750a712ed9abb5fe7324d3f2895391b0a47ce9e5527c91998fccd40200000000ffffffff03d3257a040000000004516a5165806e84030000000001ab876f3e0500000000040065630000000000", "00ac656a", 2, -407923771, "443786dd8f65fe3b133fff64050b8d32e3c3a151494251b4409829a924fdc601"], + ["5c381732042a77b03199c71016ba2208980423ecef84a868ebab2fad6bd6d3996610096cc003000000016a6f6428e8bc464e0b0141d7dab7a13eee0a60946461c7fc09932e84f49dcd8e95c66a794c02000000016a42109c3e48796f50ae6b209d0830b5419b8694a9c54c42621b1391142d1a6e6a6d79cf7c0000000001abbf1d982cdfdc546f36ff5754dddc7d6dee6b2b2416ccc958e0135142944192ab8122fe5c03000000030065518ff6e0770479af210100000000065352536563527822010000000000036352ac5c324403000000000565635252acda780f000000000006ac516552520016e96c7f", "535265", 3, 1542247537, "9dc2ab6793a6b0df4052c85de15db9f9d658412c2561e8cc95eb554ccd8766e0"], + ["07fafcb4016b7de05bea883310f4d685f6a4df87d7b02b08f5742b41b03b4cbfd18cbbe71a0200000001abffffffff03b0009c050000000001accb03980300000000070051ac656a65637aaea401000000000900006363acacac525100000000", "00535365", 0, -1088982718, "f55896573fccebb5252a5e485b5d6f9adc46d29915b844153f730bd135f7d8c9"], + ["78e35f410226d974e92b3ff804f5ac915a21b40d920d8b747069e431abb14ab4cfc43209020300000003006352ffffffff7a422d116bcd66dbafad2e83555b1f509d5358ca26d09d516e0f1b0c83dfc19901000000055253ac5251fcb2958d039c80690000000000076553656aab526555f5be000000000001ace6385502000000000753ab6552acabab00000000", "52ab6a6a53ab51", 1, 1743111409, "b5ad3a02d6c85dfe17a6d84124136801e609c427af86294e73879fc5e158e62e"], + ["ff060989039c72afd53ef83da24dcc2f0b95b3c07df61e3b734af4958ac5642f57638442f60200000006516a6a53ab52f6f8b46de523cf1aa51e73db2e27db1164b9b43f09796121215a7a6c4ed70edf8f58222a03000000046a6a5353ffffffffefd94c2cdf9abefbff325f8f9ce6add54cc326d91189e04203a3b3bcd0ff662f0100000003ab6a6affffffff01d302a103000000000000000000", "51655365ac52ac5265", 1, 1245609701, "45691d15a02f8ba65e404e6ce3f45215ed5e5bfa1424a5780056bb9e0064dba5"], + ["8f28f8b404f0c3e25b1ac7103c81f6fbdf84b6ba43552f3b5ce92e85e71cb8327a6cdf361d000000000453ab63009011c86f11ca2cfc861ede1fc5ca28e50e39260bd2e0d68588db330d166bb91e5cb057170000000006006a65ab65ac5b8a04a8586c79cb6579bc757ff87d0a841fef228480df8b62ceb271d4d6ef8545612be60000000006ac5265acab63ffffffffc2b98607ae6ccfe526a647cb09cb9d4d041d3a45557980120dc2e9d546fdd255000000000751ab6a65acac51390740040420c5ae0500000000030053acdc4f50040000000006510051526300b603c10000000000095263ac5265ab6a51530261b003000000000351525200000000", "", 0, 1619298771, "0d9be3cf0a3f68cd623229c945f232df3e70a712817bd424ff218f8710a4f8dc"], + ["0bfdeee802a4e88f724e4825eac4db7ea10d2e9c9b6a9c973d7b90f1ed5b6e2128c098964d0000000009abac51ac6a525151533f0690e15798fb1d1601a5989256b35b59ea13739dcdd61308b4f82676a76a3d71b1571a010000000365516a986cd6b9021f515b030000000007536aac5353516a573ea6000000000003635300f3c2a559", "ab630052ab6a6a", 1, 2070552806, "91a69a82f1bc0b6d2a76f0ed0f5a734e4836d1e8a386259637cf4c17943bead4"], + ["b7dd7c4d04ce0b27306a7a25e8d7584e444bd8f97b137dd1fca4c8ebbbae5e9d79db72083e020000000953ac52ac006552ac6afffffffff60934fc5ca3e37391e2036f8523a5c232f2036b598e7727f433701b2d54b4520000000007ab65ac00530000ffffffffbf51bb1b151353b8abf5feb0c57b74b5dca941af4e141831f9466e3510f90e6100000000005ef2e4d8406e1a50051a8722c76655b7f52264495630f477294418382ea5c4b0baf365700200000002655345ecb7f302818eb305000000000852ab5251ac6a51ac1e487b050000000005acacab6a65a7d6d4e3", "63ac6a", 3, 1246484725, "f6262510f43163f1d09e76ca8e28c418f6010402262b92fa55bf8192cb2428a0"], + ["a66985fd03479c618d7eadf2310e236cd5678057cefb9240815896ce1cbc416768043bf45500000000026500ffffffff52c39b05a56c3221bfa21388ebb1d3d765cb3ec045b1b51d47edbe4b64b1ab060100000005ab005200ac65ee952b146aa987a58d574a6b5e9e52510dc27b3f80adb018475e1ee7b334ce83f5617a0100000000ffffffff0347e6cd0100000000055351ac53006d8864050000000001ac45d2430300000000036a6551c8f224ab", "ac0051ac00", 0, -1993691311, "5bb72c5c2a9e8ed2e23dafc4e2c54ecd9d205cabe28f4dd694356ea6c1b50587"], + ["25be916d01a74e82c2780f7deb77769c306aedeeb232a9ce738f8bf78fd0af8640a5dc91bd0200000003ab6365ffffffff03a71040020000000007516a525351ab530bd69f0100000000004014c00000000000076a00526aab6352ecc66f68", "53ac6a6a655365", 0, -922850623, "169c142ef634046c01143987f99c8309cdc6ea7e05412a42a6c100a7a7c6331c"], + ["8cc435fc02a53e27db388313321c776d46fc077f36881bf5ea0160777607b8607d53a8ff90000000000452516a51ffffffff4b218751042e90c3cc3a39b74ddd05c43e69fd6287a783456659966b8723cecb0300000003ac5253ffffffff03815f7e010000000006526365ab6a636646fa0400000000096aac51655352516500a924d5000000000002ac5300000000", "63", 1, 1306103495, "6882a1539b0cb2d6c2eddcf0aaac809bcf13929418162f7d629be149b978c44c"], + ["2f33e3cb032da996f637e2f7594353d93287ad459e11a22bb7d4464eef7d1d730a61ce3e84010000000251ac3c6b299673b2d2c3ce6369c9fd125a90d5888aa82176db2e3c9e1fd2d8dbc0fd56bc83fb0200000000ffffffff4a6a1f555c0bfc270302b07e4524e0619808dc5e16276bb3262f2f58a6e41eac0000000009536300ac65526a63abffffffff031eaf4001000000000465ab65655ba6a20300000000005a242b0000000000086a53636553ac5265460a978f", "5253abab536363ac", 2, -1258703131, "90a701bd4095273f0216764eaa40a10831cb0c813a02fe20a31571585022138b"], + ["0c7bdee104e83872d733611d7cb2d82e3074617955a26de20fa35ad5b297e0d08e6c71dad40000000000d476c57f4cb14d15dab89ae012910804e58ce82fa0415897def35cbf5691d2bd2f640eec00000000026565ffffffff2f4746284705b7e78fb355ec897209842809e8e594570c92fd06327bc81316f90200000001003a5c275e18a9394cc886a7fc4626fc5d316fefb18977684259f64540903b6db99739ad3b030000000363636af54a83ec0169203004000000000363525200000000", "655353656563ac53", 0, 714378206, "82c6e13eb93fe0057ffefe34f35fbbb5363dbc40aad2be8b2b985e25dc4e70c2"], + ["3f78c1c00268ec033e1fc90df402d7d26ff618eff530612106c85bbf14e890b822f6c4e75003000000016acdcf5b38e5c63e93d65a3058cfac5df83778a8dc212507a1f11eaa29a96ddebe188f0deb010000000353006a739ecf330188d8a8020000000005526a6300ac00000000", "6a", 1, -187006471, "be42832ad9d6234cde2c19eceae1165924e7b2a92de3a9766e62e8da8936459c"], + ["bb9aee3502ba9ea44ca12669fad4f4592e71a5b786884f08a293b17a47a412d0bdc92efa1f030000000565ac65005197bc53332488898e356aad96001d9b062e5a71b73c9dc55c98d2a7b903beec2853e4b760030000000900ab0052ac65ab6a00163661fe0170a2f10300000000015300000000", "525100635165", 0, 1172041981, "1e2b28b27180b3bd818a27bd95fa1c12807fe26bf6a68d5ac057d4d479bdb645"], + ["273a2ff903addfbe6a5b4ae74151d27fe532252bcbe44ee447c7c2b364c044c31f517d3b08010000000751ab5351636aacccddeb521e87324eae471a9b314c4458d279efd1b7c10f7ac2283a7ccc9c7db0ec1bb671010000000091a02da324d6d80935319e67fcbd3227c7d47f5b0fd104890570597bd7cd08e79c1bba660300000004ab6aab53ffffffff040fedfe01000000000079054601000000000165c15e71050000000008acab63526a51ac53e851a100000000000765ac005300530000000000", "005165ab6a", 1, -525375363, "0e97709f93bfd47bdbf93c6746915e53a594e76b2c889a62dbdc3561e972f261"], + ["c11277f60440ffe697cef5055102961f9fbef644153066ea567df4ef4b7b857accabcbd5cb030000000152ffffffff8dbcf7a1a19a408403478e92175b3132a6b98005c060b73873c6462fa6e77feb0000000005ab63006a53ffffffffcc191fed8fc68a060e2ba90cdbee97ad9e84366fcaf7c02d47f94b9145b08f160000000002536affffffffdff07613dde298cf5748a44251591ba96486049c79a66aed330f71a1854fb03902000000055353ab526affffffff0359b65900000000000165d5363a010000000007635351525352006c0774000000000008acac51ac5265005127b27f31", "ab5263ab515151", 1, 1356161610, "704f6a511813094852c32b42ab531b5217edf0fb4ca34a9030881d807ab8fdbc"], + ["8e337e7f01ed2fee8a714949d4515bb0a3ff265306ec1595ff571fd08cd8d74206c788e19c0100000005ac6365ab53ffffffff029e5a1f03000000000952530051ac65ac52ac64712904000000000263511a693ec8", "6565acab530053ab00", 0, -2005224240, "36afac8be31b4dc535a3e7010c373c1c581a585d03a149336bd50fe574843f3d"], + ["76aa4f5c0375b5c49635cacb528a4cebe8d7c5a296c2e85fb22bc907d9046184958f4a8dc90300000005526a6aab65281e4e58b9ae031142ef73bac63b3e4639b38686ed69dbe2f477d7def5a8a547a5c981fd020000000563636a526a5889b104857e8cdf1f8ac80a629032c59c509cb7fc9cfbcfe45958d138a692c7e26c65c503000000050063656a6a76874c0e046477f904000000000600ac63655252f2d4040000000000056a6553526aaa002e02000000000400abacac1d5da402000000000253ac6bb25541", "53510063ab53650052", 0, 1719488634, "95b75adf31c58ad01a95cb180e22d5740e1654ab44a614854aa246f13d76983d"], + ["0ce107af02bc08cd83fe5f7e22f5810be2546e4646cfb1e073318d09b0cd6226da621c1846000000000765ac00ac53515100f3ea5264fb7f2b70f8437c146c51526ac7367f76bb68a7fc194a1614a8e87efee9e0780300000009ac65ab6351636353007fd707b3020fa2b00000000000045352ab5314e1cc04000000000363515300000000", "6aab53ab", 1, -266289336, "037cff07837cf1b2be5fb169231ab37aa80b515a229c17d25e7647cd79b768e8"], + ["68c843cd034386376f412de3ca33c4ed1e1642c46e6973769c94b2cb00192a72c41c850fed020000000151ffffffff79bec591db676ac3e963cff543028c7e4f1adc9cd7f5e1a4da1ac49a9bbdd3ed01000000046a6aab53ffffffff0c27a4814e57071106239d7012d2e276768baad909b2b4be268e04e63153bc39020000000253ac1c6aa3c8030d0ff30500000000046365ac5181a34c030000000005516aac53ac6cc48d010000000008ac63005263535100e26365eb", "636a5163ac656353", 2, -373388323, "af5669d590b5d948807de7e97cdb4a7c382c2a55f68ee5ce34a1fbe6f5dddb30"], + ["bfa3c47c04f1584606084922abcaf5db51c85c7db7a7f5aeefca4eb5af5e28b5a7f1a0adbc02000000076a6552acab6351890ca0820a784cf7e15829f3391f0236599e72f6070a312ff41e9c9cdac63cd5c936ab5503000000056aab63ac63995240163f0fc4cbdb8cdeae3886272cdf7c30f954a6e92b30628d8ae9c991ee0dfa613d00000000095200acac63630052ac0ffdbf2a49b38655cbadbadd15a6f254cc9928b452536ec9d86e88c0dee0f1006be68eb50100000003ab5151ffffffff02b3931f03000000000013b39905000000000353530052893a93", "ac0052", 2, -663028904, "50450af2c6ba5978ae8cfb2927c8768e39fe0115b5898a7b45c96d81fcc68bb2"], + ["2e85b0c503c7028a793345641dd40ffa8679ea3e94c2e3bf8f63f5a1551824d2ace15735080000000000ffffffff4576ca28449358b38cd847bb326c345d33288ec5fca548682fae624652dc7430020000000900ab5200ab000052acffffffff096ba2e2a7cbd037d6ca001f3f39e239a8d07ad487ead78effce7305f5c6649a000000000952516552516a630053a742252b03bac5d4000000000001658c8684000000000007ab5263636563acb9edb5030000000003516a5293cf26e7", "6a5253ab5165", 1, -1987669388, "545249fab2bf95d1201d7d7bad0181c273b2d20f4dd68c84a43422eb5803c6f4"], + ["bc42410f030181b27dd80fb7501ba8058aa8328c21d5b7151180b654ddba18e5e0cdada5430000000008535251acacac6500ffffffff865483beebefdf5defca02e706fbd1f4dc5bd34c41b167791fe3f127e0ae3834010000000565ab6a516ac93b0da2e6d1dbfa3f258f88dd0065cd82949d1a842d8abb441109abfa9cd267396814d80200000004ab0053acffffffff04629af3020000000004acac63002e5b7e050000000009536a52ab5353ab5365c4192905000000000965006a6a5153ab63ac8ff4dc0200000000066a536a5353538cbfb7ef", "53635200", 0, -1994865539, "59c9c635cf6775c19028672550b7dbc621f58149bb3b32bcb21c54f2d1ab530e"], + ["531a59030296cc91115024c2692449b9148fe7be167dd631f16f5d46c26e8ab2b16c610c4b0100000005ac65526353ffffffffcf82de5a46d7b147578914a5e06461516713a353b81b8d12d213c5a03a7bee2803000000086553ac525152006affffffff0306f81c0300000000076aabac536a526311d54a03000000000563ab52515207c67d00000000000551ab5165abf41d2486", "5252", 0, -1488166535, "bf8ca8d1c8c7a88290024c5168bbcb6793f502e519c5388a1e50564101b9904b"], + ["f840ce670192f188a4e3a0287e68925f459c049d9f8c38c418f337c813e594d2adf732c65702000000016386b142df019280d6020000000004ac63656a00000000", "52ac6a52526a6352", 0, -1983977630, "53dfd0b074d9a982ddc36ebd495e543ffbe43c8a28632ca100ba0d3bad9d9554"], + ["7ee727ea03cf5d7e14c33ccbcca946ba8cb8f67b0a8d779b932ddc67a0437317f107b05d3c000000000753525265535365ffffffff370c840c81e83377338f5a4976f7f2971de44f9dacdd277b17a3826d0e0c96d60000000008656a516a00525163ffffffff4737df8805f7fefdc44e728027383039122baa0659827f692a6383b08d909416030000000365ac00edb24b820166731e040000000004635363ab00000000", "ab52636a535365", 2, 1853460068, "d169892fc4c60f1effc3d1322f0c32c07ca4054f3b912c877133a30ff24fbc75"], + ["5beb021804a15ded0fdda1ce0a77a61344fd39141352ab3776e8244abe16636a808ef86615030000000700636aab0052ab13211cf6565cb3e9666fae7d780894face49d27e598212a0a84eaa7d95bdb5c23e2bcd7d0200000000ffffffff7a01dd026ae460317246bfec8da949939a1bbeb219642d7947f5033a167f4b4f02000000076a5253536a52acffffffff3fb1071b79ccbf45d93f3f6db80024f927851817e4b746823011f77e6ecb99a80000000005ac52acac6affffffff031b100a0500000000066351526a52ac98d0560500000000075351006a6553657e38ad0400000000016af3abedf6", "ab6a6a51", 0, 1471778039, "fceb10e6c87d01015f6a53d11b8c33bdeb74a8c87e80f231e210c098089792dc"], + ["83f9b8de04d820bdc458c113ad047f2c09d5b41dd39c0bb01586a31dd3b6ed52f83e1ea081000000000200abffffffffcb0797e33f3ef597943e429b6c2774eafff828fab44bd62e8964855052d6157903000000026352ffffffff796257704675f4c0dc7da1232a88c127ca8b30cf3dc3db3f666be0ac01bf1fad030000000665ac52ac63acb6e7cd1b1f871a387cc3cdc4ce7bab443e552999d1ffc15d5a9c43736167de85fd9796b6020000000365ab53172fe52f01478ab00100000000076563ab655300ac513ae205", "6a63526a53ab", 2, 176419178, "f1f5f1bfd8c4369e952e7c2e5013a8e95c508f1b8401a3f45cfe8e639403f84a"], + ["f6a3dfae044b5e6714d3a32864dbe5367419677243428c46d09c5fca7e343de780d1cb0785000000000163ffffffff2eae45193466237a167b0a27801f01728b51e89a139f91b3cd0d09cff244cd9f020000000763ab6553ab6552177b4987520056299f4857084be29880b5e92e1e97945bb9e9b26ed5052784a85b8446d200000000016affffffff7886195a7f81c6a5e3e56d8d807f4a5d3bab65bb75fbf924192492f03075c574000000000552ab636353289b99a5049ca94c020000000006abab00525152bfcf6a03000000000451655100acc23e03000000000252ac78a7f002000000000353acac2cfcb4c1", "65635353", 1, 344921679, "44c88b6b33213f24364660340f3f2d3adb9c03f9bd913f7d973d994930e4f249"], + ["be2f6b1702fff580456629b73ffa011c92be519358b90eb009cc3e0a2b789d24d57ddfc13d0300000009ac6351ac005263ac52ffffffff94a1e654b7460658fe0a9cae36b72364aca68d3b2b4ab86ca705e51557c2c0bd010000000863ac5252006a005150ceff2f042626a8040000000009526553515253ab53abca55160300000000066565ab0051ab0d1de4000000000003ac5163285eea0400000000003122e5d3", "00", 1, 186173005, "ab6fe7f9f881f0515bb65bfebdaa9200916a56bc6ba400e6c8a09411bb3a5cb7"], + ["b313d65f02287b86218ebb9df1953e24aed8695994a4b96e24faa369a622c9d8834123b33a0000000003abab516ec6b14e326795f21a2e1edcfecadd1db5086db858f3ba589d3cdc25986434da2162f16201000000086553ac63005153511958d4cc0180bdda010000000000797b1218", "65acab", 0, -1111018396, "09a7f740435bf58a12750ee669b068d164cbdfd3db5d4488bc88202eea487541"], + ["0ec4176403bedd046692f1b94f74a4d62720a2a754ea725cbc964d5e88b130cc095163e2f90000000003516a52ffffffff890466034ce0f75bf41879dac5e19b077f13062f9a96e763c9473292ae085fc00300000007526a6a635263abffffffff30e51c27930a39f77b6eb73405e99496212a1ec3d62db117b2bf56163fcc440d0300000007525152ac6a6351ffffffff0155418104000000000753000051ab51ab00000000", "5352ab6a63", 0, -182949431, "6740c2d38b7702017ac5339d94423a6cd828643bc05a2527687f0f5ac2489f67"], + ["c8fb813e04ef439f358546500b4170a2ebfe3f2bb363e6ddb02de611797a1db488d70ab27200000000096553ac6553005100abffffffff2fd604f4eba5e33e65f05ac1b5283475398ee604d87fd58154f51ebcffeb54b702000000036a636574708dd4766a789d6bac2d05056609d68d980c5f9addff439265ad2026b1f9ae324dbe5b0100000002ab52b124d8b81e79312a584069b9a4a50052f3d1bac5827eb15cb5d4fd768e5ab3bbdcd4c62d02000000046563ab51ffffffff035f3cff0100000000056553ab5363a16107020000000009516a63ab535365abacb05ce100000000000553526565651b32cbd8", "", 0, 771648192, "30fd5c877da47e64910c4e0b1997506887b7e8bcf77e3e80e6f7c912215ef911"], + ["a247d6eb0237afc03efca46d8e33435e921db9c570e983cb1ce57c6404c41f28a2722432b80000000008ac00526363630053ffffffff484af8ece10be172c55b1385b07f03a0a6715d38a734812e936891744faadc2b010000000752ab0052ac63630619703201851d280400000000055365ac53ac3323bb12", "535100", 0, 2024178374, "388162e22810b10f3ffbd2116c8366cf4a9bbcfd1d3b2de74e90795ae5e71f66"], + ["347bc61c01bad9eabfe460710aed74c924d3eee58aaf2ee2f3bc778caafcc29b67a671266d0200000000aef2a23b0414dbaf020000000007535251636a00acdbc7ee050000000004510065acb351dc010000000006000065636a538c683b0200000000076353ab510053ac00000000", "00abab63ab52", 0, 1361240930, "01a03ee122fef051214d5fb61634eb7b9b55b6dcc5b6ff3dcfd3888e727ba4b0"], + ["6f02080802f6bc1c2c043fb3c9073abfcf690ec34fd3880116405212feca398054fe0a5e3d020000000651ab65acab51ffffffffe781c09dcb6fe84a5e57ba599d61541da74db8060d94bf9203e604557d1049cd0200000003526563b9851036022fc1dc02000000000452006a652fc0820200000000065265525165ab00000000", "", 0, 1490392160, "220487169f51dc3731956b5dd27b71e560c8f3fd85b28095753a79418443f7e3"], + ["d33691d9012cf0bd6a77a5a9ef63bd68260265773da338ed9699a6aec65aa6aef26aa41a0101000000026a53ffffffff02f1fbf203000000000200ab09e722010000000004ac6352abe66ace48", "63", 0, -1769901470, "54b419a119277742c8cb79198cde3015c574a6f720b2d1f961c77cd8981457d6"], + ["3d1c7bc102d8c979615684e36cf7cadc5fc1000a10e9d286f95af7622f958dac941f308f83000000000251abffffffffaa21d05388612f0d097dfce97b6816d4fc8616f102d0721e58ddfa195d1fd84900000000025265ed93632c018a4d4300000000000000000000", "65525153006500ac", 0, 1589645022, "d64d2d0b33f80156bee4b3da959e6456707280c504368cfa1f54791229a0a084"], + ["2a33358601eeedc77200b78554cb22024fcfb6f58253c972340faac619fe82aadbc7a5fb800100000005ac656a6565ffffffff025cda540000000000065165ab0000539a7e5403000000000000000000", "ac52", 0, -118456729, "66f78cd5e2b0a482e761db48e91203a70ebf21a7417ef4476bcc98e80572f60c"], + ["d3602b60019c43c71cf1c1a218d75fef8b6a2ca217c10500cb246a775a2de2a5de3a6b17cf0200000008636351ab52630051ffffffff045ec6c00300000000066353635365632300e6010000000001653ba0a4020000000009525200525253ac6aac9be12d04000000000752ac51536563ab00000000", "", 0, -63062320, "2f1a3e7a1a4b55e8926d129612c7359ea235418b31ccb4c79903783668afe5df"], + ["934f43160244f02b1a422f119ffa9b9f9c243b848863b4ef063693df694a1fb81276e42996000000000452ac6a5115a6f43366f0ac2e37730e5a5d057761097a57543f8342fcb3c8db976c6d8231bcad17330000000000612d9cfe047975bf030000000000915f4401000000000763ab00acab5352ba9571000000000008526553ac6aac00654d3520010000000008630053526500ab536664bc98", "656a525252ac", 0, -698326316, "1181f5251440417fc2701cffbc48eaa770dc43dcb76ed5ff32abd7dbd4408b90"], + ["a6a0776f0486dbee55548f6736c0260d4c91b1f4c50e07139b35788b8429a62f88b7f69bb4020000000552ab51ab000b66e26a7e45aa089e0483e0ba691a5074d13b166ee989e0d4e6401ab3f7cee00d0ca47c0200000004635365636d0ade465fbd9a0179a71aceee427e920530307a169009bfb8a296ec2c0c86dba3b0b36402000000005d3b51c78ed8b5beb199a0d3204b9fc00867289b4228439ff03b461f5ab33af61fef181b0000000005ac52acab520fccef860181729604000000000963635253ac0065536300000000", "", 0, -969328804, "b3b4e1cdafa29c54b5d3ea299c40c27f8a1b99fd1b5d6436a9cf79ff22929d73"], + ["c4a3056803195d47c63df04b2583c62e70e54dede7a971db0839e06704b40a50b6bfcf49b10200000003516a51ddb10df24aea1c9ebb7d7bf5d9bcc4a98c883a2db3099de343358eef200902c12c58ab19020000000700656351ab53515db1df8080a774cc774312e2645d04b41d34e44cf18667c7c058f809749c3390aee13db10300000000566f8ec004464b10020000000000a18b8504000000000563ac536363e9c63301000000000351655266a990040000000008ab6aac00635251abec5780bd", "63ac63", 2, 871790021, "e462d0e648057cf561da59d39a1ccd858a610109737fd7d695ad62b77f2ac5df"], + ["df9404ea03fdd736dce413c12cb65e419524334717e3fc41f3ecedad99841392da24a7cbf4000000000900536553006551515190d1a990430ec6ca086e1ae5783ccbbe0677a7427f5a50fdecdac3edb5bc5ef90cb79e6e000000000953ac52636a65636a53bf3283b78a8f2ae82afaa103b4761687d4a929426ef2c0a4c38981cc5f84e42cbc78884a00000000065251ac635253207940a203465bcd050000000007ac52526a53acac7daa450400000000015163a4c20200000000055363acac6300000000", "52006353526a52ab", 2, -1535894553, "76defa779cfb58fdb8004a384139cadfa800db581a1704e3eec2d8f441efa750"], + ["9be3d0e1040e34dddd94928a420ac7f96641cf7e3e6e62e749173c4ecb25a6ea50970685b60300000000ffffffffc5c3fec1de15a161c8ecb7a4f2d5cf6dd5f51e17de91441ba6f62f6d6c3dfd730100000001abffffffff49fb52571cc4e2793f94d46d9e20269779b6c461158442a796fc8d432e59d62b03000000066a6352655251ffffffff40144ad77bc01c1ffa48622724c1df3f8fe9d6d932ac9855da176ffcd1cd37ac0200000000ffffffff0418f17d010000000004655300538a69c40400000000008a20250200000000016a6b3f1e03000000000165f1b06e50", "ab5152656a51", 2, -144958395, "8d51bac9f1f280934f1012a906e9717f4f1998f50480f68dcf21a5f7e5ff540b"], + ["cbe9f5e0036f769748c0eb750fa8e0b27c8ed8504f15b82780ac608d7851662131a66cab2201000000056365535351f17f3f21fbe955d17115606f879ac7fed75bb727bd00a56a8eea57beae753d66a40b84ad0200000004ac5351659e6744ec6b18d014f0d0a338dac100854e9bd7bde098c494a6ee2db6d16c011f735dfda20300000004ac636a52ffffffff01e70c5402000000000300530000000000", "00ab51", 2, 401083464, "5f7c5dcabde2539959cb2648438d4adf734c052e91c862477dd37683ca0a46ea"], + ["799610f704869b3a08b2346b5559080de09490751a6a301dce9d9da5d4790b72ade85b74a90300000001acffffffff86529d4274f84fddd781e3583c0de5b9a1aba20e8bdce125ac8986e5740f679b0000000001abffffffff41438b3473bd5abfe65f5b3d7046dd984e4c6a96eecdd92198b59981855861f000000000086a5365abab655365ffffffff42d7b514ce0163d8b888f6295f7d1ea5796e1f1ff3d143a4a5e7cbcd6b89b8c20300000009acacac006352510053ffffffff020ead76010000000007ac51650051ababda51c603000000000465abab5300000000", "", 1, -1960505623, "6f848d848d9750b488ffed75136c05b3796f8eec0a158ba66b57363f7309cb6a"], + ["6230bba1022bffa0ac9c674c5737a7cbf5735e0f8b8237d6b49cfba1f876d9f1bca745f3bd03000000046351ac5321c4e77c48c1eb7b3eaf349918e04fa80decef788c5da46706b8225972f5940bbfc480d4010000000663636a6aac52ffffffff029403d50200000000096a6353525163ab6a6a751d160300000000015300000000", "", 0, -136674322, "18c287c5617da0a0db9a37db6a3d6958f1d3eaea45c75499acae0ea9b5f620b9"], + ["247ecb4a03b64c2edf8b4610664ba3b82a0ce008f02153095a7d05309fdd649b71a285f000020000000300acac66fe115a46bea2da99af5856d8bd383d60f963dec9b37a1eb3eebca0e3810a4aee1d1d540000000000dbf3c6ac190e3cb1567eecbd387c5a698380e6efbd651cb08f9c2ee2af53c17cb7ea32480100000002ac00ffffffff01207b4402000000000900ab65516aacac6a6a00000000", "6552655351", 2, -1832356916, "8b22f46b32332d792985827a81c764746b380d0d3e26132cdeb9fa0675504858"], + ["d1fb9ee8024a203e5b39a0e9330cb621c20590a9e22f2b4d879a29287b9c7048372914889701000000005a8345c4da032252c2559758a8f14671963348ac7ebf4069f83d8fd0fc5a810dcaa37e16030000000351ac530c51026101289f4b030000000002525345feada3", "5265655300", 1, 1917786592, "94cfab45118b01ad78e19ab4b20b73af825c9b66bfb17966fd1fdc7ca316ebf9"], + ["2a3384b0022696f250f3fc7c2c65d665605dd372597322238b01dc49150a7f334090e9b3290100000008535151006a6a5153ffffffffe0eb4c16f2c6859d590f90ba4d26916af449c253d71f5e56295d78328a7ba7fc00000000046a526553311c91290297ca420400000000066a510053656ac2d9c60200000000010000000000", "516565", 1, -38224263, "1fb6981e13af45b9169f20300558873f44733e3e4ed710be76e2766c14d48a23"], + ["1936e79e038a94eea234915096d9b97fd1007a266e2e88831a4ce28f46db4099d390a71d7101000000045165516a17662f447b47707ee730356665138308226efbfeff7baec8773a7d0f243a4f9ecea9e11e0000000003655263ffffffff9273c6c4a2ad5c42178535ce50eb5eb44994b500163c99e487bb7d0264e446c4020000000951635365526563ab52ffffffff01e0157204000000000952006351516a0053ac00000000", "", 1, 254904045, "7ffd14e30997f25bf28a7e4a71a2b336e5babc62fdf8de7af9f6c146bdaea15d"], + ["89b416ac04d1f7bdb965f1f8e6c596cefe57c1bee8010c13e6e3e6a132a76ac2c531f8a5ec030000000265537ff81cbf39c11ff5c58ae3d008e4ab4d29979e4da1e8abc0903f4be657638c6f81eb44540300000002ababffffffffc88a240681746e9371e10ced9fb529785045c3e93a7112f864e429f84323d1e0010000000352536affffffff0c6298e417afa3a02cb33c02b107a555e91220ab46be9f75064fe24694118c050100000004ab516aacffffffff019dd4d502000000000852526551516365abaedee879", "51ac63ab65636a0051", 2, -231220635, "92aa464ad1f9b717be96248ecd102e7b33168f4e7e3454bc5fadf340960e6fb2"], + ["f0615cbc0251f98a5aaf4d9524bde9afc41ccd4dae55305740e0b5fdb20fa6d3f03e904a5d01000000085365acab535363657d3fabff5de34ed8982f4ed04c4667c5d73e29999948deecf3ee616b7723f064c295d96a010000000365516affffffff01d53cb80200000000045253530000000000", "6aab65ac5153", 0, 416125557, "c28572759cd266fbdeaa426c769cbb947522752480e69d8d5de8779e47d76910"], + ["a0403eab01bce03f0a539d7244f601d96cc460786d7630036ead47f426b9065fb2a1f394eb030000000152ad7d7a70049c90bf050000000007ac51ab005165ab1aaaac04000000000951536a5151005265ab9eb43903000000000800ab5151ab006a52ef5ebe01000000000351ac53074ddedb", "63", 0, -741831223, "a01c93921de42f7d4e7778dbd552aa3712ed8ddc6ec4ab8359b3c80c03fb1689"], + ["7b12a84a0382a7b9196100591067506b311aceb9aae07220792132c8ca3684bcc98698d42f020000000653006a52ac53ffffffff355774920d365fbec700d884b4c7f19fa02e87941e455fade7a804f4af0b612203000000026552ffffffff0fe491f59a495f27142e9afd0f656f8127bb67f11d814a72e90d1688cef2654e01000000045352ac52f04e8c380378019f050000000009636563ab526aab65657f70fb0400000000000cc4250200000000075365516363636500000000", "5252530000acab", 2, 152646765, "d276f71402d38550a3ea1d4b1b02592eda753919042e0889a32c215f696ce4b8"], + ["a1e2871704d2c5b661b66f9c81968c1dd7799068192c9c9cca22b5f568e966c16e67fcdc6701000000096a6a000000005153006dfcfdbce5d08466513ba667e7e5b55a6ca291c63381c404daf1e0fc3d3d9151e0665c69020000000300636affffffff669e6a88b5406ec636e8dd29448a28b0e68a3c9af169c13391dcae388d2f338a02000000096a6352515363516351ffffffff7365575ca28cc2eebf11ff5cf43bb206f0b90cb9d2a27e373b323a30c93b8cba0100000006ac0000656352ffffffff03a63a3d0100000000000d6a45040000000001531aad20040000000009006a65636563ab515100000000", "6a536aac53636a", 2, 527486548, "d7e18bc808121542e96dc3eb20a8996b727fff7e3680386e48ee2d579a24dc75"], + ["a396c2e30224c73e19a98db3c79358763cf7595236215a90733dc5ac4354ef82c0ec619fff0000000009ac00ababab63abac52f724a8db0a786993b672ae7557dd50936daff6341e63ca7623bbf6314233e7875f71b52d000000000451ab5200ffffffff0154cef70300000000085353ac63abababab00000000", "6a6552", 0, -1687352731, "9a1dfa4ed2b5b7fe9c06d872c868198c08043f6859062a7bf362c156e9347c4f"], + ["5e0939e202d9180b0d6b55af93e42c5dc10dadf7b500d840d61cad7033af7a8113ec71625c0100000008635153ac65acab65ffffffffb183948e3541c2f7019102269661184f28af2c828c3bba0cb02856018765b5ca0100000009006a63526a525300acffffffff017aaa730000000000036a6aabcd26010f", "6a51", 0, 1091981401, "685687a1c6e22636de7adbc4d0b7caab3225aa018014e122ab7761a60367cb63"], + ["1571863e04010e3ef19f997f07c4c8e8e77f7a80e6bc32220d40af2d49a58202057c93544c02000000095251ababac6a63ab63ffffffff202a9b19265ea9abf2cffda6be32fddc18e851a7ab965f8a4bdece8190c1acea0000000000ffffffff39c1d67b8e06c72da9223ce6a3b563238f6da893d631f744735556dff65b8ab5010000000900ac53abab6a516363243537f211a96f015c6767494bcf8de225f111017103b85c344979c0af08a76a30d7f36d010000000163ffffffff047d9db0030000000008acac53ab52636565a05d0f0500000000026a6acb4d4c0500000000065163516352650b375d020000000005ab535153531f4b938e", "6a65ac5151525151", 0, 113910907, "d1728f57cd92e79b3d817a70ec6063b26fb89adb03ab0c87242c5ed885ed5eec"], + ["28e2309b03c4f22129d2c71e2086fa832dcd103882632b853a5a6d2bff0fec428e5523ddb903000000075153abab635251ffffffff7c50a3f8e99af518316962ae42be8887350f01d39ac820eca09c02cad907e6e80100000006515165006552ffffffffbc19bd44d700913dbae075c89c3e069f68462ba1bdb8d35f264a5bf3dc8c1f79000000000965ab5152ab52525151ee8cf6b3049c236f010000000007655251636a6365dd577a0000000000086a53ababab636353d527280500000000075251acab63ab518570b60100000000045165ac5212a44897", "ab6565", 2, 908546556, "16b4f4d1c5118269ce0a42a197f44e229cce7d8688b67062c9d1da14bb7e0eac"], + ["b193e5e20476d7cb81f48b17b42f18b59052eced611b4614417068b0bd04a4a47831054db7020000000300acabfffffffff36a7fe1822c51c6dfc8e7e4c9ecb6fb790bf84b7b5ee7286accbe366d5df3280100000006516351abacacffffffff4a6c1b3f05aad41cdc57a04c847d4c6a2517fad43b72e04f43f9064d40a727db010000000551acab6351ffffffff1b11a90b0a9b9fd74e56da8b380351b686d66a32983e1e3eeffe2b12bd2ca03d03000000055365abac539750ddc304e5ea550000000000035351651e6e1f00000000000800ab630052536a6aaa9a56010000000003ab51acfd96d90300000000056500ac5251b7792e26", "6563516a6a526300", 0, 1008207055, "21b72668a9ccd4fb9f9a1d0f67e47d1009d36e0ae6018c2ba82658feeb682ccb"], + ["14f29c0501040f8fee52e0be4bbc521b5bd3d172bedeef38c7ce2799d524272716789a8dac00000000050052ab6aac1f65e87e0350ae3e000000000008ab63635265ab00ac204e2d0200000000056a00535253033a0f0300000000045265ab63113b4338", "6363ac", 0, -1105168316, "f7fd133c82f68f8a6031524b6aead2622367521ed2b632d70d5e9750cdff87a2"], + ["cf8d7046016c93fcedb341d664ac9ca80fda07ccf5e6834b0727bbea58a95e641707bd4abf030000000663536aabab51a98ef6cc02445784020000000003656aaceb7cd90100000000076500536a65526a2f0fb198", "6a", 0, -953713807, "fc351fa67b3aa151c6fc93ef0874fa1aa2a24362548b646943cc411da4de2f70"], + ["f659d47d02603091402ccfbbfe717d483c42e9404c2656c174a037d766b55f85d470d9d9f50100000003abac65ffffffff4ec8da0d6d9f12beb26836e002384de823651962694e223eb281f18877d5fc1702000000056a6a0053acffffffff04cf43660000000000010041abac0300000000060000ac006a51d43a4a01000000000753656a5200536513389f050000000001ac00000000", "520065ac6a00ac", 0, -621928847, "3406b6fd562537a1adab32c80689a695652d4771f928ae3849cc94cacca4bbcd"], + ["bfc1fade04c2783353f94d7d3e504276b1edde63f777c3551bf09aec1f1bae9ffaee8d9abc0100000008ab536aacab516a00ffffffff692abe8d2a1c7f96d61b0c8c5d8807af257adb4aa058c99ba7edbae8d49118ae0200000006656a6a6a0065a34e62a4fdf0313840bf6cb9ac8b5da817ef4bc1c7e79da9b858a0ba22156b025d6e83d303000000016a1a746a6681741b7384b3a083bc67b3b7c12bb734e891e84a0293ce9801ed62247c972e240300000001ac400bbb2301570c0002000000000038dbc0c3", "656365", 0, 1879809730, "4dd9607e5d25ac3515d2ddcd73e8fa99e113879a4254dc64bcdb7bb6d1390364"], + ["6995e1c904fe7a728ae00209d4e2c79ffb7d390617752789dd558ccd5c6dcd67d9e61622fc010000000352ab532c2f93ce92fd778712c327f0892e0e8e8c04e3cac3fc508fdf611e7fa7ccd11898d9d3c00100000007ac53636a53516572a5e5d95b1e65176b9164d3d8a3b391a879f6da0d1c61618596a9d48d17245717d02ac200000000066551515365abffffffff1fcad743c4bf5186231280fd4e5cf7c14e73fae087c4760f5b98188a499ff6d80200000000f9b4894c03fff8f8040000000005ac5252515255e6df0200000000065300525353ab5c1874000000000004650051ab9faa8e21", "65", 2, -1731271586, "4615a1a7059f49b5138f66e6baccd502d87b5138cf724225fa04b915cc759234"], + ["e7552bc3036d489b8f5f6ce4c45bed939e9787eefa239bf525ed56f25a4dd61930c618511a0300000005636a51ab65ffffffffa2eda051be8129c2d46304adc6f2609fa43468fa34b8929ec68d43d7316b9c5b00000000055300ac006353bde7f568b78bab1df0a97268f7cdf3f88fa5e6979c2af4204def1aa59fc89c4a086d9e0000000008acab63000063ac65ffffffff04f7e15103000000000763ab0000515265b89feb02000000000563536aab659e53df050000000000ecbfc5010000000008536300515265536af895f8ff", "53536500635363ab52", 2, 1186243940, "27b3e7a7924a6cabb9bd977a01cd1950251167b8d63e3082bf61785d87a982ec"], + ["2a61b52f02be89426c08eed4b8e38cf72938727066728a508c96d898e7097fee2c03e0bfbf0000000008abab526a005365ac092bc7b844cea859aeef37c0b651866c382a7d0b28987310009dafce41237f014d42db0a0100000009530053650063ab656550bc5e53014669ff0100000000066a63ab65516500000000", "65ac63", 1, -1692627743, "e1fe9691378cdf7339ef34ba0c28effe0a423dbcc94172614d20dfdfab25afa4"], + ["bc1c5c2904cd54b80ab2380ed0c903d6d9c13711ed5c9cadef30f7c14d10a758546dd55e8d0000000005ac6352ab516ee5a8b89e21593d066b76486a16c0a11cab869cf882cb8039eda48ca7159672d2f0584c0300000005acacacac654d409dcfb0384188bca6088ec77129cf5b4af25ae72f3e02b8c8bb9892149aaea9bb4d5a0100000009ab6a636a63acac53ac305e4f3c323dbe9cff9f6d0f3597bb1822c363138b7947dda0cea1d2e15b0e6ecc6e3c820200000002ac533be8356c023bbccd0500000000056353655352d4e6c603000000000551ac650051a8121794", "00ac6a530052", 3, -1567938194, "0b551b38421cb359f7aae2c9085a7094c5532922d6e2974ef8aeff701aeb48b2"], + ["2b2278fe034ef7999c4cd5f1310d220178d9c36f9959612a56eb5c09df8291519812f7eb6802000000066a635265516534149c77d7e91e11fc971a69545cea9599001d19c586b31ad719f3fc06381491a7beea1b020000000551006565632f7e51ae14c2a2bec867f139bea001ccc6aceb863b6f28da92698cb99c68135b18e281fa010000000900ab53ac51ac65636affffffff02237abd020000000007ac65526351526a40e8a9030000000008655300635365ab5300000000", "526352", 1, 41332929, "c05c62661dd2a912580ef3c37ff94b5df20138e9fe6bc97d68478fe4593a75df"], + ["94b30c8102cd3b6992c7d62c132bfcf4a7f8d50a28c6dd57bc818f9996c640390a6603b55700000000056363516553942c8d55e87e1b76a592c6d94a0e54478a286571d5f5e6a6b59533a7d296071c5b7929d001000000026565ffffffff02ede431020000000006ab65ac63525275197e030000000008630000ac53656a63821ce8de", "6a0065abab6a52acac", 1, 1923372023, "692997cae1b81347c3b136a482718ced50fe16e6a45a58ea7083073fb970002c"], + ["d7e8af1f03b8de97ce717a276add6472183a67d07e490a8e810d64225b2620b6d735aec85a010000000852526a6563ab00511afd4f1e521c531da3ebccac04bae024a33ac640328f5774c0d8431e2e6d7a9459067673020000000852526500536363ab149e0ad994e928514b1c0b2ae43668ed829175881de67410e3399778344d2b15d513ecfc01000000070053abac526aacffffffff04df7bc0020000000007005153ab52525168678a0000000000036553ac341d4805000000000263650a4d1b050000000004ac53ab5100000000", "53ac516552516551", 0, 1349136583, "eeee8d4c81535100ee258237d11238f0752e7e2e39447d90ae940ddc0b869b59"], + ["6539aa330304f96c5a7dda59868cab08a6b9a31b649d7a6304fea605aa6a58611f02369f0c020000000265acffffffff9fd1b29581c88a9ca3e29b72874137275876690315e74f1b9025f961e0b951e00300000000f6ce3a58149ee883517451beea2822cca72d5b0c8a2415ad457fb8a1c3d7bfc9ecb674b6030000000663536aac6551c3dd133c0224110a020000000004ac516352ecc8a8040000000009ab6500516a65516363db0920bf", "6aab52516a", 1, 1706238826, "af9c311795b758143b6e7ef9ba0e1043d9bbb14040e180350f39c28beaee3a03"], + ["540b5bc9015ab47e5e690e59ed2d1764ad355414eecbe92a9d386303cbd467ff1e90167b2e020000000253acffffffff03024d8e02000000000265532ca163000000000000bf71a3050000000006ab6500ac006a53ea9008", "5151ac", 0, -2025477006, "69af304d31a68ad18107b12f96e6f077c5796db3ec1aa63689d44000f4d5f124"], + ["7ad2480d026587dcf0c5266fba2f22ef11b5bf82887984692a58bcb4002d74ec60af0b1bed01000000026aaca69764ce9353db5d03cbc94a4e8c2639be7a39d501ff597ae0109afcf57d6c36f7d45447000000000153ffffffff0204d4d404000000000900535251006363ab63b7de38050000000005ac5363005200000000", "ab6a516563", 0, -1164586520, "a6ce382f0b558aa9482410c8700750e4f7bbfd64483c8893bb9e997ee7575f6a"], + ["baa8606b040fc7a729b6ce836f42b117a154761560258aff11b21445c07235eebe600da2bd0300000006ab00526a63005ae3687bcc105118af0ebcf7f6931f90d3b764f161edcda3da1e2203deacdbe25c42482c0100000007ab0000abac6a51ffffffff01c015d9be32599e4a375ed40d163c252618ef4e802544fc8a44cc2655a2ae11010000000020e6b1e5fe0e9258db1df434f5c26a148c9a896a17dd62786ba2597cffb3dd1bacc00c4300000000086a6a63656a65ab6a06d2cb0d0132015604000000000951ac5365525251535100000000", "536551", 0, 204224734, "4d6171946bf80b12bd7847b80537f7b7b76f57d5692e90869b377b7f1ea76b6c"], + ["cd512976048481bfb784090c2318f79df6f4c6aa00d03c43832b4b4af886ee383da82319d40100000004abacab65be4c1adcb890c3715a5845aa0cd038b365c15ef8abd1bb1c4c169f57608dedcf535790b9020000000252abffffffff2e195758cf857f56ed513d18aadb65c6dc3be762703ac7d169d50ac097ebf796020000000465006a65ffffffff4f8251dbc24c7f8a04b2525367fdb5041d3ec7ad08acc5640125f4345fc8823003000000075163ac51516565cfe235340278f13000000000000953636a656500ac6563ebf2a1050000000002636500000000", "ac63ab65536551", 3, 2125510482, "7030d1fba2daececcbd5de1a8cbe1333b48f62425d93a477ef34dfc09a131151"], + ["5d7d32b503c9a30a37e63d279fc40ea5f6f2cec3fce91fc48f9a9014a69552c5c6d59f705703000000026351b124f238e8aa096e1c92af56dc728a60506d07f9fae735307c634bce6cf2a7e362c24b480100000007ab655365ab526590b07b3300f6e1f8a0b5b8acf6b35407693b872eaa102c6a03a024b96885053850b2da4d02000000096a53ac0065ab5200abffffffff04b433c9020000000003520051b128740200000000046a52ab6a9d93b603000000000165f7c19d0200000000076553655165ac5365a7f3ea", "ab536551ac52", 0, 2040198598, "90082cdc304b4defbd7631da05131e8ba62a19f08a32996cd6ecb5dd58fa4ed2"], + ["6a9028ce021c34890ad28948469b0c9442c7cc5c049c8f5105ab0f1105fc02c8e619d4ee4b030000000265006336a744dbadfb0628517fd31c3ea7ee62e48ea767483f26c16a5a35a0cf7d4c268aef6600000000066a516a65006affffffff01124cd304000000000863526aab6a0000ac86f3a910", "65", 0, 1878773328, "bb61a827dba9e908f302749796855c18d972191fcb8069ae6a1732352ecd3088"], + ["1fa849b8010d3cbfdd3ddc9d8eb73aad43922a65ae8ff2bbf48d840cf73c98ecf80e0f7a370300000007ac6553526a51abffffffff02a47497040000000001ac71c727050000000009656352ab6aacacac526d607d14", "5200636aac52ac52", 0, 775791965, "8a922ee50e9ed0c7fb9b8de51fdc70d5358042d42e02d9a073a9b37e4c1ec8bc"], + ["79288a1304f78641d7d385483f958436ad64fcda99d4bd94cc0f4f845f92bbb9c34bae546d0200000003515351f14d63ff354b927d6e12147744c25e9aa58de29dafc88f39629f6681182b9983b81c8265030000000853635265ac536a65d6b31748fd7cea5d471cebcefcc513f17579ec2234822af08fc2fd1db29b7167411f0ceb00000000026a00c8593d27614c969d1c7eeb72db4a481ca6aec09024b02ddb829de912fbc6d8dc94f7561303000000026553ffffffff0406d69b02000000000152cca7f80400000000008a4a2803000000000963ac6a636a6a6a656387638d02000000000352006abde39dbd", "", 1, 839857915, "9f09c6c9c7a9da8f15efb19311dfd939ce8d69fc1a6df4997c200a7375d333e4"], + ["208b7bb503c3e3ad3679235e6975cccce666481b34ddd1bb9e8589f71da5fe0e663b84cc4803000000055353ac6565ffffffff56072b38debd9621201c669e95f1f99b40817ac4a69b1d118445c940ed3274bb010000000853ac656565656a63ffffffff713e73337aa32e1099be44f48217d1da45c68dd998f240e8ddf0592db16ebb2d000000000452636351ffffffff02368522020000000003ab5251a917c005000000000263535aa73fe6", "536a536552", 0, -503008026, "303340db5c16f9cc1f66a0681fcb488a319e552132c45335e2e8c84aeed77ab1"], + ["3e9749400474966803febe2d9315e2f3dd4a9725cda15e9805168e0d2f83eadf1ecea61310020000000752ab6a6363ac6a768c392748c77dadcc36d09e16f59ca43799ac7fb4490599b1efa13e5e104f1f8272f0ae0000000000ffffffffbf017c939e722aa217278a2235f4868fb879369b00ba5eca99b75003d05179da030000000100607593ab9e7e09d3c2c558b8ca8129db4e785a9c4089870f61905bffb411b01c718021460000000000ffffffff0311875205000000000463535252a47c6b000000000000ff869705000000000963ab51ab635200516ac8deec22", "6a53ab51536500ac65", 1, -477215642, "52e4b88cf8b70be52236902a242c4e9bae449ebe658aac0a38bc8a9f757ceb2a"], + ["5b2bdb5a040b5f1a2db645d86d44ce3f18ab1a143208cc023ac121081db13d245d141ced5303000000026aacffffffffa700527860e10f8a5010af7e97cd60fb32495e0ecc9a05dc4b684eb6b789a02c000000000553ac6a6565ba026c7faecefd002b4e8f46c2bf467689e486a0564cb64ca644ce4408c266f03d7396b403000000026353d67b3fa2ff4567d32a475d71039bb22c50440d434b137b32c6c73416c977f293f18a60b00200000009ac5200650000526552ffffffff043e9fbf04000000000953ab00ab51ac526a52d3d4cf040000000003ac53ac92b8d003000000000852ac6a53536565ac25db80050000000009515363006a636aab6a00000000", "6a6a", 1, 276215140, "13964d749e5c7f8c8ddfa59a18f42715ec0c510824bff8d4cad4717ea5981b73"], + ["9809187c01b850bbea4e36f8f95202259d1fd5263d0759788213500419f512fc2cd6c7a3160100000008006552536a6aab63ffffffff0111caf7040000000006536a53acab63be507636", "005253656a", 0, 984164416, "4a2523b2c7c8828c7fb7f81430c9008af0fff006f0b44651961d60a84691cb38"], + ["3d7fe5e7027d3e4fa8749f41cce733ac15f5835bf9ddbc505ab418e27ee01f134491455e11000000000153ffffffff43ad657f30bf9fe0e3ad459edbf0bf6915123836460f03219b1f28b0255bffa30000000007ac655265ac65002d7c8b680232a71204000000000451515265fdda50050000000002abac7777474d", "ab636551ac", 0, -1290573211, "b7c0cd07a2a5156fdf43f70f7e3c9ea53a2f5bdbec571c2def9bac29d981ee72"], + ["f885ad6c030107c64b86bc48d84d6c4acd38e821e1fa4f85ed526bb22ba44d6cb116cdf7c8010000000752ab5151516363ffffffff921e29e88ab04d8151ce94b5c61bf887cf62ae3c2ffc65f9bd9282b9258441f202000000060063520063636012b9cdeabdc6eacb72a9ac392bd52b4759106ede71723590f6bfb9651f5e2392f458d4000000000153595c224b02d59f9f050000000003515151765cb7020000000006656a6a51525200000000", "535365ac6aacab00", 1, -674909570, "4c3606fc55f70cd655a10d60df591b29dcb063d47f097edadb10b51fb1a404d2"], + ["f1a2a351018a997db9bb2035b89e41b631757375f15f676e626c678d04561311be453532ac0200000001006023c28804a16ee405000000000565516552ab9a934c0100000000095365ac52536a00005356bf840200000000090052ac6563acab53ace5dc4a03000000000353650000000000", "00", 0, -1986332942, "617dc81d4a9059a568e89cd2dcd79f60baf394eed58d7f9a91e443e404754502"], + ["e99d6ad103ad4e3753a3e8c070f79e00293160201fe7a5334d690a399b961b0bbc8a9459860200000004655163529de4fdb090472d91db8776e81ceffebe698419c5ee30207c962b847817c0045d53fc7f940200000008005251ab525263527a4d6de7c7771be105666aa578cbf9165af07f44c3bdecc67de82febeeb103bb3f29a6b60300000009abac535353006a65ab8cdc710201d3f5a1000000000008526300656552ac65f22b9ebe", "0052abab", 1, -380169134, "50605a31c75b70829610391146045ee6b6f24cee26f672bbd54ab7d758f4f173"], + ["5c48f083042cb30d28cf8fc46af40d04629e1162f58f984a5042381405a5696aec39ff049a0300000000ffffffff7786567b8ff8c3f2de57b4b75932a5481f72076773b2999a84e428a3a0134a400000000007510000ac00acacd28f2220424b42ac1a8bb902fc58ed05ee83dfe0a682edee5f4d6deac6d1b0ea6830bd460100000000ffffffff4c0b935326e7a9f94579107d04ad5a5ec65f448ad1914380ead5abb5a8e8c7fa0000000003ab0053ffffffff048ff907010000000007526553635151635a456c05000000000300ababa7db7f050000000001ac4992d602000000000753acac6aab53526cad98d3", "525200acac6a6553", 1, -523524149, "a6f50ba4f92c483ef69c8ec7b2d29fd63b3454a4306e4866afe1576eb76ddc92"], + ["cf40dac5015c236ab2996223aa69d414c72a2230d0aa8acb372a7356ae9cdfc53100e958ba0300000007510000516a6a522784fdd2048db303020000000007acab006352636596fbad010000000001657bd81300000000000015ceab040000000002ac65cad9821d", "5200ac52", 0, 622176474, "fc337ef03bdc89607894ca00ffea4f24e3cedf456718430cf808e1d994b1eb45"], + ["eb52f530032c82031e64968cee204d8d05f8cd5ecbaed42332bf38ae0491351f4a669bdb4b000000000553656a65002e794d5dc173f313e413a51240a0f1bd87712f176b30dc5e873209254149b29e36df6f070000000009acac00636a6a525353ffffffffdf066546d44867a293bc48f6cb0a400174572068afb40c8d71b3e534751086ae0000000003acacac82af464801b7ce4905000000000037b73458", "51", 2, -157415476, "62338ad6b9bfba626902b0ba4eedf1472ba94149fc938b3b37a69f8a6771470d"], + ["51c4407602551cbe69f70f8f0c3a2da5fc3dbb7e6f62dc6a75aadf95c72673af15347da984030000000763ababab525352ffffffff53f0da3836fa045ace8938601068fc45174e9ff7d1c9ffb4b82505acd14a8df9010000000163ffffffff03f6cb9104000000000800ac65005353ab0080038400000000000663536553656ac01d2c01000000000252ab31790c30", "65635265650052ab52", 1, -2055629863, "16d7b58d70901575c94e8d883ca60b7430737dcbbaa761a00e2c6622a3a57fb2"], + ["28293a5404470f3f03ede35f65bf95341e5c9a132346d715dfdc0a3f286fe534803fc1e56102000000076a535265abab63c85f8e41705bee4a8eb211137ad565eaf8ca4e8850cc6ce9bfcb9083d756e98a747002f60000000009acab656565ac0063abffffffff4edc86c0d12b4754348cf9bac4569419dbf50c1d29bb0e047512a4b63597410b0200000000fffffffffbaa68b2abb3a350854f5c3827605a622e08f7f0c6854a71bd848de38888d8ce0200000000ffffffff04afab61020000000003ac5251213b6c02000000000852656a53ac516a00101d4a050000000006ab6a6353526a19befb03000000000965acab51ab6300516a00000000", "51ab5165ac5153", 2, 470205652, "d3c945a46a393c35af1901c7a499a8c524d3eab018dcfa1af01f69fa74652cf7"], + ["ece343e90139801bb843a3114a5cfc9b2a91b26c3cfcb9518817255b1fdb4fd2ff6b7c7cf500000000025251ac1407c304b015820400000000076a53516352636a1cf6a6030000000005510052acabd0e84e030000000009ac6563ac5163ab6551e06d8e030000000001ac00000000", "52ab6aab51", 0, -1689869724, "681e8373340cfb397991bb2fb9b537bb06fb100883b43e8b78c859fc7608ad19"], + ["798aa55d03eedb20ace384c768648ee1c811c715fb95f9e8325a9a6f362b167780c453b17c000000000452ab52abffffffff2e978ed56bfeca15246eb120f3c1a583abc97fccbe6010a7a515632a5a746ce301000000075251ab636a6aac8b6787bc7aa195078675829c91384897dd8e4152c06841e0c05bf661069de199747d33af02000000060000ac515200ffffffff02e2a3c7010000000004ab00656aa37810020000000009ab516a6aacac0052652e3f2ca8", "65536363", 1, 111197516, "fefe976b6ac5e3a76b0112ae64016ea756c54f5be74877d42b166fe147b6e985"], + ["a1fd49ff031c950f52ad72ee8cc9dcb35459c57b61ddfda9db5d7d235653145c3247cb639600000000095252ac636a6a6a006affffffff6ea43642d96c9e7d1ac9e269e5f4f3e46ff8c4060fccc0de3cc46eb03d4d2185000000000053c0d1111fd9d89cacfff55aebeaf383e6a95f997c5711deb421949b0dcb5716d87b8d1f02000000075200ab53ac005166da9b4e01db36920000000000085251ab006aab6a656533c26a", "6aac00acacab5363", 0, -344085823, "438ac63e95b831516bd4022740ae046391b38aa590d5be160b6b0cf46a77319e"], + ["b6fc1d5c0468a1f0c108850e84de4b0208743a5f466eda3b35c5d6fd6dfd3819f60f20fe1e0100000009acacab63ab5263515336ac81b6555db0d93ef9e4cdb4c128f955a6b01aed9f2c07f346343a440e249a0dfe29180200000003ac6a638dfc2846a1c40e5146c6a41a0236e746c36476752bbc4e404b78cb971c43ffd032dd00140100000004ac6553650b88b03d149060946b1feba743b6476280a89f4df6fd37930c444cda6f6be914bafc4424020000000452ab63abffffffff01e381ec0500000000036a006aab80d01e", "ab6aac65ac516aab65", 3, -1862194967, "6536663396e43f66824ccfe206de84f8ee503723f5217d8f65172687a2bf4883"], + ["7e1c48e901c6842e04acbebf25ff611fc6d88ae30cd7ed0f921c9b53fb2d50f10c71988d6d0200000000ffffffff0486c9b0050000000003526a6a417f5f03000000000153c42492040000000006515251ac0051db6dd402000000000000000000", "", 0, 1702864107, "41e1cfeee697e6d2b762a1bf62ac79208adf1a91b05afe929b532d29819b387d"], + ["0146bbde02e4c42e99fd7cb8cb9f68c1e37643403c64b11f5cf7dbccb246a83146aea705eb0000000009536a51ab53526a636ae8772f7b9ea9f3f1b28f3cb3c315141426d0f53ebf4461d979c1e0470940bcfa3b154f8e01000000086a65ac53ab530052ffffffff0214e655040000000005ab51516563136fe9050000000006ac6a00acab6300000000", "ac53ac526a", 0, -769350529, "91ce08561b4fa366fc50018be2f69102dadf98ccad340534ef7e71cd178674c8"], + ["1327f8c40216dfc5e314d0511d91f9930914b0d32707b3b2ff15a3f1555a0d442d0942acdf0300000005536aac526ab46b7f4d734cf91aa12d75be862dba97cb1e77397698f6946d75a948cd9c3be96672397902000000076a656aac526351502789f504ed52ca0000000000020063e84bfa040000000002ab510b387f010000000006516a00ab5163488555000000000000c5858f5e", "6aabab0052ac", 0, 1175943244, "1b4abd1881579bf42625565f8daddd2287008a9ca44412b3564bedd0b7e29231"], + ["356b125b03765caecea418ad11b6e26b4c801381fb71001d63cd62ab01331b5d70b54c150f01000000076563ac536a6365b005d06519a4ef2a32e10c3e4f07582f81e0a8ad8f12eb08767ebed561ee92eb013cb9b1010000000652ab536a5265ffffffff2e34ce72cd03f74581a383d30b87ad6873ad51f18142bd58044f39317e7471a60300000008536a0063ac00ac52ffffffff01ad700204000000000163ce0f5a1a", "51ac", 0, 682690923, "e9bc99382b3d718a95ecd11deaa6d95ab9263618fb8a4e0bba851722317ea36b"], + ["437240bb01d5bd8d4f3427bfd57050b7371a73b1d7da8518f30a04c2868c70c9930932f0b40000000003525353ffffffff015d1882040000000009536a526a6a52635165009c5af7", "ab00ac6552", 0, 433644485, "e8feb49ce7a2bef651c4a74bd778c9182340f8c0494792794bb96602cb312970"], + ["0084c2a6041cabc95b97c34df20598777cdc6743b8b180cb1d6286588e91e5887c02adefe50000000000ffffffff95099d89b9fe635147825d7d912c33d83b1e1e1f90418002bd8a0d18ef401258030000000200ac3d24d18542dacaf83c86fa0ed27bc66d9b069f1c3e8ae56d2d8878876b36c9e173e57bf0020000000752ac5251536a6affffffff56506d1faf8bce4593ed2da5d2a019ab1f66790c69642dafd473c8a6bd99b64c030000000800ab635163535253ffffffff02be63dc010000000006005165006563b78bca040000000006656aab516a63952ce561", "535151ac", 2, 1450556129, "0ccdc1205fce33ed5a9862328464b00b2aded5a6f927d861b950fa2d169e5ee4"], + ["a0bd2e5e03037b3d5f39011e6b779ab914fbfacdd6f3c89a3942655cce4f09c72e64f71510010000000965ab536500515152acffffffffa98eebbefeca22eb5763e2c6ffda40376effcf1495ccc296bcc7fcd601d592f603000000046a51acacffffffff918601e81040401706d7e75f517f0bc7fcbb9fd8a6fa3ee8436a70e8cb3f4932000000000963ac65ab65ac525351368f9aab040ce4ac02000000000165fa279b050000000002655313bc1b01000000000851abac6351630000f4a99c000000000005ac51ab63006657f9c4", "6a5251516500536551", 2, -470065854, "f08321c9020bc85e763bf679a6b0be21152aafd11cb6295cb1e92f261fd14a43"], + ["8cead3b601ec1ef759600908ce5e1c618e348786dcdcd414907a7d131d9f4f6213f9466da8000000000400635263dacf299b0301da34020000000003525151eb4ece05000000000965ab006aab6365ab65246235000000000002655340fa0823", "6a", 0, 794961149, "038be12a529813e970901cd6273a81709720397744802c37ce85442e539a42ae"], + ["5075bb180293bd46aea174957a72f413b2ce1bb77b1c21d76631f7f23e4a93270c3bc4162e030000000900ab006a5263ab6565526ab9043377c0948b0dff935c4da751ab61f1c1ba03a5cbc1d9e7142bbd423e186c9a7d030000000565636500acffffffff02d7479a05000000000400ab6551a4773402000000000600006552535200000000", "6a51ab00", 0, -28056125, "0ed28ecb98e229e02dd14c28e0f25f88704916bc4f28b66ad71791c6000fd3e5"], + ["341972af0196d81df5672495d0cd9dc3bf9527715e0399265ff435c93a88798d143ab53a4403000000020000ffffffff028fc6c10200000000055165ab6a00c0eaf1040000000009ab6565536a656a65acac7ee8a6", "", 0, 840466269, "43224bbfdba3b66d24e7446e6cc90b5568cc62e5b0e58cbb95971c5678ef3467"], + ["de41a59e0214cd40ebfd6da150d4776ad9ab95eeab7ad7171665468508786a8169efc79946010000000152ffffffffd29f622123ed919e7f421d667e3c154db1c4296b4526a781bdf6c474fde0fea5010000000853536a6a525300653392b8db02782a24010000000005acac52516a06489105000000000865516365526a00acb1ceebed", "52005365", 0, -1948942395, "82063b773ee00370119bd7441daa711881c9b44f6cfa7bcecdaac37cf8c110d1"], + ["27ced0d201b9218ff20911466fe762d561fc413410f7f4a2ec4e0700fcdeff003ea7f93c9f0000000003536565ffffffff0236c65d050000000001003a03d20300000000045200636a00000000", "6a", 0, 1176070124, "454e62a05ddee4f1b586c13e394894a9a3e41eb6155052d025069fec99c6b44c"], + ["c56d76fd0209d755452cd3a80ff61d46438674433a9244677bfbac2bd017f3ac574e4325b902000000086a510051636a65ac5fd269a5f1e7e5aff088494d040592487cf8772f9b276041ca3b4b3d065cdd08fae5a64c020000000452ab5363ffffffff04b785c70000000000060063ab5200538881520100000000066a630051acab647907040000000003005251f90c3a02000000000752636a51ababab00000000", "636a516565ab", 1, 1805726933, "fa4c607cf62d223e8b87955e1f252713697291bd7f7c27ae1c28c00cf118cece"], + ["7e41db6f03e966fdda416faf34ab4480f35d36fb11a0b5f8212eb683f0cd9075973a4a69d70000000003abab52ffffffff136e9e0e73802a02c39ba220102b0e08f88550e277f0e46ea671ad0ca4bb195d01000000020052b37f49afab570235a1df1990da27b7ea7e24e5e4e3f70890d3aa686b453b80900cb8a7fd0100000008005263ab526563acffffffff04c1d42d05000000000153624b6f030000000007655200526a6365240c3f000000000000ed7b58020000000003ac536a1eb07186", "", 2, 1709251434, "97331f1eacbda19e7b22e2dc26b73469565018cb47c295fcd1c7cfc15fa0ada2"], + ["db663174037ac5fffcc3ea1203df51b3bac5e7390a982e0e44600bc141151258f26ec457b30100000008ac6300ac516a0063fffffffffba2c8528f0df429c9e8ebedfe01630aef87424155d0b30c801eade209d4cac600000000066aac5152ababffffffffc05490ec0fd9f66432540fae067bb56943468cde511c19b5611bfc55570af5aa0200000008ab5265ac63ac6aab3fa9ae720466cf5d010000000000fc0b6e0000000000096363ab005251ababab46795102000000000300ac6385a69b0300000000030000635e28cd4f", "530053655165", 2, 244944618, "eb13336ec4bad68d4fba0c890af00327adef5155f63572ed159174d85ec5b7a7"], + ["440d48de0145de53ba03a07509c0b6cb1ed4ef04ae89c2567f6b6fb1999a3fcafd33acbc47030000000153bddafeab04c587460200000000096a00525351536aab53b24fd600000000000152154f9e0200000000026a53a0ff94000000000006acab6363630000000000", "", 0, -1880184486, "1fcea898123000b4c523ac0688af93b84740e52285f6dfdd1be58f79438e6348"], + ["fdb63e01038965e82c4cab5e01868bf30906bfe2c5fdc3ab14c8c568b01eed03cf6b40878702000000016ae6d1764a113abf95161a7abf95b681afd5781b879802632e5d4776bd4e5afad774ab188903000000086a635152abab5252ffffffff8e52d89e5fbffc7b2c27012ef12d3304e3c5adf0a677cc6290e271d8209cdb970000000000fc382dc504224dad0000000000056a636a51515fb43a050000000002510071d83f03000000000565ac00520056ee86010000000000ae0689ae", "65ab", 0, 130259699, "367e21dbed7eab50cc00f30dc38e21354ca4deeacc32c35f281d2f1157ab8852"], + ["a3c776bb02fe6c41f5d651edb57864bf6dcbe68ba42a7ad6d4c68e911aca61d1994ee760d401000000016555fcbfdd0e81adbadb7d9123e28a83ba55b9ea4cb6af8cd1c669be487be2266775554acd0000000001ac7d59bb38010fa0aa0200000000066353656a005100000000", "006a63656a", 1, -1934574010, "fe5ee58c623fa03ab71afc8a0de68441106c1c89dbf5c867d5902583a824668d"], + ["f2ae7f0e01532603d18fafec305be22d349bee202db7fd18edca2360e9b24ac7add9688b0b02000000045200526affffffff02018f7e0300000000020052c1d9280000000000016a00000000", "65ac5365", 0, 1889845099, "79c41acca813eaa5dd66898395bc5edaf1545fec3ba902d4c53bea7a46d27e33"], + ["c74f200a0377ee544a65302d70f94e9cbf0f72520d56d0d44fed9bb5ad29635143ba8766fa0000000000a2ae0dc7a5df6422df9a0f9f3016de686a66b024ba82227dd96d427fdb0af6df43a69ae1030000000965006aab6a00005353e47a03597fc0256655dccd2f03d942a3cbf481c07975c32043c469b52a591c9cc2ce79350000000008ac6551ac63655300ffffffff0113ffc605000000000263ac00000000", "", 0, 1484619391, "6caf3b57db491d9e27a09bb6ce984a2fc33e79a8d8f4e86c242a422e6295f7c9"], + ["2948919203222cd14f135a3032e76dd35817d8b060ca74a0863c7f41dfacac89bc33a2aace0300000006630065ac51654d24c7149013cc29d9384846b4ec279bb3c8adfef69bf3057d4af9c64fd913947fe557030200000006abab6a515100ffffffffaec9bc7dd90a11078d7fd2cdbe928cbb29afb4bfcefe7477642de5c0914b27510200000009006552005352536363b328131402da0aa404000000000953ab65acac52006a51985e3d03000000000900acacac635351516300000000", "ab6552ab526a00", 2, -1760535206, "e630dabca77bfb0dbc59dfe5927f82f931b489db2a5d809a10ae45cdd77efcde"], + ["2bff1a7203a609b02affe84080b215064bb1b91da69fd8470a6805c2603e6966752fb5d10600000000086a6a00ab655200acffffffff97a67252d069978a77f20c04dcbcda7cc247b895f80b9a30bd7d661399c42819010000000963526353ac51535252c74b8a67afdede9987627f6affba5bfbf4b0171892b8fd96abee88e08095cc10a53313ba000000000700acac006552acffffffff011816d20100000000046a6a5265b1d1090c", "536552ab6a53630063", 0, -565363205, "1e5e4be3a31b5614f4d85aeb0a649ca04cea4a00f0ee6d1d44d69c30940fc4ac"], + ["2a590ea8033f1b7ecb6f398ec6676cb6502de811af0777579956d773bb0dbd7157fed949e9010000000765525165ab000025ce4f06768a0106f09f2adbb9a35ba12dd731193afc754976ef31b87ffa6f004da49c6c01000000008aa9207a9d8775036b38cdd2b382e35caa77c947e7f0f6c951b6328a381102dace38107702000000076353636a6565ab2b295ad704b0b5900500000000076a536a5151516552fd60050000000004ac63516aa9841c05000000000763ac5365006553a35d990100000000086500acab6500525200000000", "acab00acab6500", 2, 869635149, "cea3bf8dde18299be5734a5a46eb3e8b5ed014bc25fd9e82de5ec9a21194422e"], + ["e6b0b4f80233f7cad63e5fcd843a3a6d42c80b5b7e7bc4c43a0d9d20c478263b7e9fbbd005030000000653006a51ab53ffffffff5e0a89f4d645826345cdbaae3e5b96d3dec27c279a90b5ae1c0949df1c691b53000000000451635151be789565023f704e01000000000963abac52ac63ac6a53e28ba50400000000086a5300636a6a6a6aa5209ee0", "63536a0052abac63", 1, -1850898621, "3aa9c3a3f472d2e07f0c71daaf37d9959d6566f3c4e07ac761350d219bf413d3"], + ["f07465a602a1eca6e0b642d14a79349d376a8eaa19ec428a162206703f4b313706d8256c650000000002ab53ffffffff064e7d55b508087684de74f906c8a427c8f4df601596119de6f0744d723e2557020000000152ffffffff02094bf402000000000153ca3904030000000003ac630000000000", "ab51535265ac51", 1, -431086777, "920b8e9d47360fabd7ea439b5d26e0d9e00abce92074cfa264a7db869472bbad"], + ["f7e3c469036cf3ab52121575d3ab29f81666c879de95a65c857651e4e6f96667bb6a218b15020000000027c3cad68f4c313f0356da2865a2cf48405412041e0b3b2a7b490d41d0abac1cbd13fe6c0200000000ffffffff49cf65d8e1d46c5f90aeed076d3a1b8c473fc49a610a3898bb70dbb89312e21800000000065363ab6351ac5f36feb101dd8e470200000000055351ab656300000000", "6353", 2, 651564244, "dc8bf61791587ed150b969e892d147c5c2021c3e0add5e272a443ca93039a43f"], + ["b2b6ebcf02039e414e34d2c609c2df19f61cb6f82cae1ba00824c96264f4f88e90580b0094030000000600006500ac53ffffffffe725be5e60bcfad1ac515b9ff93a9fc9da14995d6d67c1b8556cde1df5be87a60000000004515152526d68c05c04876b5b0000000000036351536d9a170100000000036351654026f7010000000009ac6a52ab005351ac5107818604000000000000000000", "ab65", 0, 1980335853, "aacc35ef405f2f54e0d9d94799fb2579fec74c2f065bce039bd93fadf38461a1"], + ["f08379fe028e324fc5b17901fd695d1526bc8896b4183b20ee493ac1572e40f3bc03cea4a8010000000551516a6553a538976fe341bde37b4f8ce8ad2c4e2087767e1e0ccf0c65d4ad7e6c553c9d50ca38eb3b0000000000e4dc41720431a39b0200000000026552fcc42d0300000000086a6351655252abace53f38010000000003ab5165d552780000000000035200ac00000000", "52516a51ab", 0, -1344771859, "596475093118375dfcdb127c3b0df1333a0fc6fdb3f54134bc2c0fb186800390"], + ["16ffe45a0122403f00e019df6eeffdc1cb51c468bf7fd4506928c8d31a115e5357ccb30fb90300000004650051acffffffff0266839a010000000007ab5252655100636d89e0050000000007abac63536aab51f8b3d6b3", "53ac52ac6a655352", 0, -2048531243, "f59b02357fd36dc5e46cb7dae2d84c8fad3b0a05bcd9afb213d0b1822e6a9dd7"], + ["665fb19c03aa46c8fe66b1db6124c1529994ddda3acd9af6f947095d7dadc77a865feb4b9300000000026a538d40f75f252bbead84dd7bc3227d86feb492f03f529d47c95125596665a942ab926361010000000003536a53ffffffff70fd2722421e1910aafe7bab3f04957ce9ad5d2b62ee60e501cbd971da27b18202000000009f728e9e02cfd3830000000000096a51656353006a65abe6e4140200000000036a636500000000", "6a00636aab6aac5153", 1, -874372618, "f84d7616d74ed64a825b1ce082fc934f7332846378e31511b55fba84d75fbedb"], + ["0bef59ec041cc412b0be32762c660769ff9750dd843325a50148d31b9a60f2702ba65ddd4402000000007f6303fab006b8c2e84f430f545f068cc36ea7cd5da30c8f0c79f495de93a737401b374c0000000000ffffffff5c345401d719f4181c9782ad1a08aecc4f4dee9f0ab2ae32c4157576600d62c50200000005526a65ab00fe5961c0613f6bd5fbd3240ff29d01eac901d88cb97f9da059dcb58b8b0ec9c24a12069c03000000025351ffffffff0362d8060500000000065252650063ac88c1c905000000000900ab00abab6aab6a522223e2050000000004ac6a52002d35bbaa", "", 0, 505306858, "57c70ed0c2707f27a8288002c8b67e07194e107334aaca35f41eb095a3645072"], + ["04ba147f0104e5d46eb322b4bbc36c7f6cc4ff252a3d9a1b80c4e00f70eb4dc151d22ee87d02000000040065ab6a8b95fae40121025c0400000000026a5300000000", "52", 0, -453751958, "c59b2b5fd5b3312dfadd4a2c74f123fecc6b04e951951175e776c33900b2346f"], + ["71c43bce01fc698ece88210b27c80e8d281f4e72f9bda0abd7e3864c24b48db6aaf2301e370000000006535363ac636316692ea2039347c1000000000002525374942c020000000004650000abeac9cf05000000000851650063ab526352418d4e00", "5263635165", 0, 1256941529, "b946693f1b77580465081f01f849d04df7a5b1f603fe744e29d55449259808c6"], + ["cf5c38d001b983ef9a4d2733ef7bdde2a62c2efd7e94c732b000a3b0a8577e190434d11e9001000000036aab53301db67c029bbb21020000000006ab5163ab51abe9c07704000000000852656a516551ab63f1ee7340", "ab536565", 0, 223879251, "ff83ebbd562a38a8b00e90ca2b88e95e8cbebd9c728cccb3766442a882d595a6"], + ["ed0f4305042c2e1dbc963f2fb870edefef9c849f0b300a993769ac0b695c18959a25ea28d001000000066500526500acfffffffff8bc178eb1631f80c2534d7fe837c8c1e753cb4c84e3677ec4e513ffa69052e603000000006f3909fce3cb1d0079881faeff6c286c2a29b50495344dc8f93bd90fc7d7f05a9a633ff90000000008535253005253ab00175f9843c075069afa67490ceb123fad67b9724509a1d48914e94878d6a4551d0966b0f7010000000553abac5300bc6e2ba603634cb7050000000002ab65da5c210200000000096aab5165656351636300a78400000000000000000000", "ab00ac656a52", 2, 1055998818, "3355a0bcb6e635ac8cf5dd08e0450a20caab6ecf4467105850d2d96b0cbd93bc"], + ["bc1f06f90449039a5e6b4734cd8643af36eb51e2686f2aea6dc0671ba82394c781231da3e9010000000152ffffffffb07e9da6c7ca3dfc325c9ef8ee1853a9588b0e0d9973fa8cd8392fd62429f7f70100000001acffffffff5bc88dcbb614b2e610511c494c0864b45a7d6f25060f0ca54fb1a1817c1f82cd01000000016ab7c363e63d64fe0dd56be6fab52a33ce2e42db6362f7a55cd3961667156996bbb8b5a2480200000003636500ffffffff030b5c84020000000008ab63516563005151f54819050000000007536a6365525351c1abe800000000000000000000", "ac6551", 1, -1776636323, "9c4fbbbe54297d93a26ac0d604d2ec8cf2235385b68bdc12bf67c97a31b0de71"], + ["5e5eee9a047284d91b4342ebed024cbe3be938ceb3a3d3273129ce169b714d989c0a84a7a40000000003515365ffffffffde8e187ebaeb087929f5a329b8693666265f2a9231e8df3d05d3129f24e8f83a000000000200ab9a89205c768a77d08ef92a01649770084f1eb0b8a48f98e28cc3d1e9d0268e3601b034900200000007ac6a5265ac65515429d5ae61f87288c9340be37e8d364a0f690442324dd22470496f7e58abe9e1509163290100000001521987a05f0137e46c02000000000852520052ab52006aaeac03d3", "63ab6a", 2, -1726847766, "3a0fd0d2cb40af18df3ee469599211acb6ad02549b8d6029b2045dfde0ba0822"], + ["1ce6894601304b450daf7b43acb80947907dd2fc94cd5bcb1a385f7d4548119fd00a98097a0300000004526a53acc660282a04d58206050000000002ab63799979010000000006acac6aac6351688cf20200000000085163656a6552525179c688040000000007ac63acac65ab6a00000000", "ac6a6365ac", 0, -1497066422, "593457d064e069c82fc6437fd5e5e22a6e6c80740bf9ae8e1a10c3174744aa5f"], + ["1587593902454908fb1bd49592b292db938a33074b7810aa7b9aab2bc72486281c9109cc3102000000095265ac51ac53acab6af220ceb7c817032a67d45a42c06d43b42c3fe38faa18e6d7fc52899c2cb0267b49cd1e670200000002535283bf4bb40118f50a05000000000663636351655100000000", "6aabac", 1, 653042791, "f48895d18b132ebdcdbfb93f2b71842d60b52991fe8bc61f497628f9f3d8bc86"], + ["24c8472d028ad1586904ec63d15829a7f60354a4eb07e22a383483a5528f99c6e75eeb71ec020000000652515265ab52ab17ed80ac5d80f92dc9740d2f230a84fd468b7cc895e57421b200112f86a20f0c6e8f5702000000090000ac520053005353ffffffff04b065c60400000000076aab525252ac0071a34c0200000000030063532ae398000000000004ac00006a6d782404000000000100db363170", "51", 0, 255452359, "934f422059585681d4f44a86832fb0735c223a2a5531476eb6329030200134dc"], + ["db45648e035627eccaf947c28f67fdae1a6397a6d6098c0233204dbf1b1bc67219a513c7fe0000000006ab65acac5252ffffffff5c85fa70d3938dfb3e18fd42e67f6597da0bf6c242c79a666457d3aba15981bf00000000075163ab52635352ffffffffa306d3fbe656e5b9d0c90df153840fce10866ed67a52889163aa821be79bce8b030000000765ac535200ab638376226504ab77ec050000000007516aabac53005171bfb5020000000000deb1eb040000000009ab6a526a53ac53ac6ad8acd3050000000008ab0065ab63ab00537f2c6155", "0063ab52536aac5200", 0, -1826443541, "66df833c2710335c139e21400fa5f70498304e851b3d6514537596f5b67acaf6"], + ["727d923901ec99fe1d0635de9af7e57aa4d885a8353833196ab56aa773075f31c9705adf2803000000026a51ffffffff035e31aa030000000007ab53005300516a9d4aab01000000000353ac63d8f04f020000000008acab5300ac65526318ecec94", "", 0, -1243714846, "e2f71d605e4a322bde55fc2a850a9e2b39963b2b2bef44efcdf2d4bc4504ae26"], + ["37f3103603192ae12f8efe17dc0fdc80a3ac96fe3c868cc6568d22f6c22907f66a630b3f1a030000000865acabac63516553ffffffff9e59c6078a94ce22f6e5572dde50299e976cd0802ae4cbc94786bf8aa17fb0ed02000000046351ac537299233dc4ceb64d977b628128e4d456dfb6e06eb0123eeed5486df82d531b4cde6e52230000000005636aab0052ffffffff04b8fc450300000000056a6a6551654f2aef0200000000095165005365006a63654e7e580400000000076a650051516552b089bb010000000007ac53ac655165ab00000000", "abac6a5352526aac52", 0, -1099146020, "cb6db313df0206156e99720cd6f0170071eecc65be1b830aa126a281748c0789"], + ["095eea3604c928d15f99ebb9a52e3640db5ef95fcccb3cb8f44830143018e6b903409be36b0100000001abc218b44f7060a64d9ff5c65f6027165c4ccbdca2b61c18d85d3fec253a20fbb03f30346f0300000002ac00ffffffffca6edce330ed59b127a3afdc84c3af7c9c7fa54ddd0f06ab8ace6bdce1c10901010000000363ab63fffffffff110e48d6b2d368b70d990d2ca059852bccfb7e1a79ad4079fc4ac95a878cd050000000000ffffffff0442f80d000000000009ab656351ac6a516500fb45640100000000096a6552ac52ab6a6a517398f5010000000001515c709c0100000000030053513244ad4f", "6aacab63536a52", 0, -260367490, "40ed3cda1e44fb1bbba1422f2d0c89420838e12059e48a646612a98c9c0aa5be"], + ["3c175f7e039837c3a1a4a6a6bfda31bf3e155ac5b3a431c847d6cb087357d0114a880c9204020000000351526affffffff6fcc3d91551f9bbe1dcf7f162337681532b7de78df59f17f28766b176db26ca20200000002ab52ffffffff7799ddf42ea9ce83e1ca5332c129c6ce6820cdb4d9b46560098ed3d6e6e32d5c0000000001ab12dd851c03312d7e0200000000016aa1f66700000000000553510065acec6021030000000001ab7cbf337c", "52", 1, 316012415, "531d027855f2c4ce44c8379307a512bf680dd0e73b3cabf3a7b37263c3e5b0c6"], + ["2aafadd4041204e0805d47376961284074612e37b58e6dfc51a35fb0143a24629c4cff6a2901000000096aac6a6552525353ac2f17136d9f66f5e3388f0f89ff4665760974a558c80d6635b652b3b4c32d64abc287aa2102000000020063ffffffff83282d11beb2e74d82f5b801b30b946149817b80147854d0645bf7aa5f1cb2ea000000000563ac6352ab5a5bb65f06a0fb27ddd70609cb92287a4d6e97487f85c7d8ec3cd906e46ae84b53f6136700000000025152ffffffff01d9dceb030000000006acabacac65001ea61521", "ab", 3, -1186890393, "1ffd4dc64d0973c9f0d084d7939359561239be07336e686971c5a23eb159f623"], + ["e2e77e120397b8995cdeba10ad51049077d665c8daeff591e2fc870b86b37c87935daeb6c000000000001df1fb693e92c5e8b2309108b5bca02d5128ca0c60aae402ed40f9e7c748cdc5c8d513d60000000007ab636a526aab65ffffffff274aafa4c973d931bb746172d1812a5b6cd9d5b5a1746938749f02a5b0fa9ec60200000004ab006a65b7ef45b204096cb900000000000465acab531bdabc050000000004536552522ddfcc0200000000085363636a6a5352ac62218f0500000000066a0065ab00007977bcdb", "6a00", 2, -1843142703, "40a32a8f100e8074c3d002d06329b7b245b52a88ddd49708559bb2a11bd787eb"], + ["8bbd1477015eb3a0facc784a41e4f6055bc4572d99392ba998a87f4d4b801ca15df64e90b902000000095300ab5263ac650063ffffffff0374cbef030000000009510052635300acac6345303d040000000002ab51905da0030000000009536aac51abac63ac6a00000000", "6a6a6500", 0, -1839960476, "bdd22ace0484c3a7f8dae254ed60d0994c983f030499822ae610e05f4109c3b1"], + ["72f3ef9001a474715807827f0086766061735a5136e690948fc9164ef526b9da52e0d318540200000000e61362800385031f000000000004005165536e92b60300000000086352ab6552515200d4019b0000000000076a53ab656a006300000000", "525363ab53", 0, -868418448, "0038a301877986e319f1386b6efcd0c3c1630a68caeefb4c64423e3bcc0916e0"], + ["139a05ee01b4314c82b88a9a79ceecb2447b71833c358a9d55e06464f1f7d9c6b3c46731e102000000007d4680f103a7f7b5040000000002ac52f667e20200000000086353656a526353002307ac01000000000000000000", "630065", 0, 298103109, "03f4faf13e41988f417194205cf9ba8a4350b22b31eab5fa810c9dfb9af18bfd"], + ["a9d399b10155b994c8745e6dc4207deca9b41858a8b53696da9a19f66ba99059f94ba4eb7a00000000095165abac53ac006363ec7d94e502f241c8050000000000106997020000000009536aabab5165abac6300000000", "6a6a53", 0, -1716484001, "a13b855492f37408c6b94d2bffe56586d35e72141cab188a3ca88c03ae6145a2"], + ["bbe955e4034dfb7edd27416623f1fb85a7e49a613dd3754474baf3af40f4c58b241f07a696010000000600ac5252536affffffff4acfb7ea0e52a0bfb973d2538300435cfa2bad621363d72f8a4671ab3404bc4f00000000055165535163eba485062067ae100e658ff28be246c4fbffbbccf152ce533ac93dd71c994cb81d60276b0200000005516a6a5352325d7e6d034610ee0000000000003255db000000000009abab6a5263656a6a530ec7300200000000046aac65535675b881", "ab52636a6a0053ab00", 0, -585414817, "809ea38874dc08040e12b4a76656de808fc1f145ad1ad2902a2b3e6091b1c7aa"], + ["fe05d44004703d4e7465d11578a7a0b6265549b3e1c1196342f0069bd8bd05cfdd38ed7a4603000000004b56b84004829e135b716e900ec57a408feb1ae288c3346f036125c6bb5bfba6217881fd000000000452526a538835eee70a7e3a65dcf8f5b638607fc1ebd27d43d348f3940b93d233a463da83ee525c210200000004ac635263a5bac24424ebbca62b29f04f00525b1623ff59f5e8e3c61b7a6b15a57a5b5f949c1081940000000009656aac6a6551636500a9d7d36502f6761301000000000300ac008ba44b050000000009ab6a63655265ac51659ee347b1", "006a6300535151ac6a", 2, 234612189, "7ec0814fcf117f8e8d4ae6983e9fc19afbc76c6c81614e5f990e8bfe7ffba9b0"], + ["86111c7801328fccef252efc48e47d41cfa6435a4201c30bf09b5aa5289212bebf5b4d217f02000000085363ab6a6a6a5200ffffffff03d52b7f05000000000563ac006563a6a880040000000007ab525353526a63c9187e030000000006abacac52ac6500000000", "", 0, -2042950318, "9fe39b1da7c3bc3940b90d3b6634e28f869487c5ddf963f4eabadaca5d00b1a6"], + ["0c2ec8e1028df54d8495c8a780d7b1e25576a9dcc6c7c2f60d26747c52207147654fa3b52d0100000002656387c10f4d0f9b17716432b1c2d373fb924cc7c8c9ce132a3d90932fcaa3db078d5aff0139000000000552ac6a6aacffffffff030d0a42050000000008abab6363ab520051d464ff020000000008ac655353000063ac6f24270100000000000ab8f5c6", "0065005151630063ab", 1, 1133871296, "0fb1261ac4ae64b4a64f229b60d00555bc3bb5ce29c281bbc2c79a17e7f11bb9"], + ["da78b9f803e263d9473aabab2212e0fa2cb1c1e3f3b36095fe5cee026e1f765ca4561fbc0902000000036a516531edbbf97bc7b898aa4b69b520fc06949c4bd92207eb7e9940f025dd952b7aab229e24020300000006ac516a52ac6affffffff3de285be714adae125e7ad8fc79d6cfe80e2d062afa59d0321a1cd79ebcbc2200000000009636a6aab53516a6aacffffffff01ad56470400000000075351655252525200000000", "6353", 1, -1843178131, "fd24ced522cee4025e8cec680b9f4bd2fe6e556fd48a314c6bc32088ab8ea45d"], + ["421a343b01c1e08ec6bb4546d2b8d970a4e6097cd1263464124b4c4d49093c6d5be3fd62b7000000000365ab6590943ede02e79b7c01000000000352ac53ff952103000000000963005352ab655300ab00000000", "", 0, -1233634082, "c7ae2cf2cf0cc3785f9c4f1268e3a6e70b7b7027d425b00ca40809b5b1f27623"], + ["4ad0b41404fc04afa38eaabc736cf34a2f6c896b6ea9b6a8496600767b0285b3f7ca196c490100000005abac635363ffffffff15a0d372427999a2ec10c07871c16aad33f9a08bde8cf8f66dfe335c074b70460000000000ffffffff4343f956dcbba327268500f55e0818a596f8a9d3406ada9b7db4638c064e1ded03000000056aabac526affffffffcc9cf315ff22266e02f2588d94db5774cd596726e35c3f49ab740f8b8db73a610200000004006551515748bbec01563cda020000000006525200ac516a00000000", "516a6353650053ac", 0, -1970257281, "259486996552417f287d1c9879d3db90e6480d85f1cdcf91263fd0edf88159e1"], + ["07fee4f704eac679ec1231093580be1a873775a981fe71e2c0954afd6ba2695ae3bdc5b0f20300000000ffffffff577d667d1341836cde32c01d4c7b612361d970b61529be2a88f6670a6c911b6303000000020052fffffffffeb1af1ab5770704c4a8b288483ec8d06ff77f864c0fc8773569f794d90e2ee402000000066a63006aac00016ef10fd7fb1402d30415c399cb174087a04b1ad301c6b6c790b0f4223d72085a985d4e0200000009abac516aac51535163ffffffff0215df390200000000046352ab651a98f001000000000152bf9874c9", "515251006300", 1, -2088516522, "77ccca0e1c52196b158ce3173e9673b60157eea5bb7a5fa0963c122f077e07cb"], + ["3ad66060010332df6dd6752da2a1beb730b08e55f2bc01daa0cbfac60a6f2f3b433c009a3202000000026553ffffffff011244f90300000000010000000000", "65", 0, 416837328, "a4248c171282dfb2ec3377e8d8b823941c100d2d0e5bd88a73215ced51ceeaeb"], + ["b17c73c1024a1f035a0766fd13f3bcbcad5899aeba9a8921fb6d039367f22b5305e92c3e5902000000076353ab5363ab51ffffffffa0fb1e7de163c65fcac8520c203830ac801a5bf918f6bb157b7c77eb55f0d9b9000000000552ac516553ffffffff022e3244040000000008abac006a65515265fba34304000000000100d119f317", "", 1, -1700846884, "aa2bb6befdd9125deda681fda37b2d6a96de234d6445e5ad14bbd4e81aee3086"], + ["af19faa2043f04b309bfba276be0def391201e7f50d2125a9dad2b07a68acfaf431a96eab900000000085351ac5263ab0051ffffffffb9c9069f7659fdcb859407c1f1b736d06b9f87d2891c302e40c3db05747233ef03000000086353516a53abab51e6cb8e1e7adb99b164ea6e12f53a2ae88c6535774c16be7592f0ff569b8f3f1513deec4a01000000025152ffffffffa4772cbafccb89643d64ff41ab00b7b0b365a3026e921626fdf19a3d447e4353030000000652ab51636a6aae78eceb03e241b6000000000003516a516efe470300000000045163ac52b29aa1020000000008abab6551ac526353a670fe75", "5152ab6351", 2, -24567324, "8dac3650448ca45a205d5525f8f27dcb803781ff8d56cb3dbfe9be97ca781fee"], + ["bc63714c01707a2b67bf19abbeffd87e5a5351fd8bb3ed2b6524f881e829a8f4a25568d2e80000000005ac5100abacffffffff038829cb010000000001ac50b6b9020000000005ab53636aacf24bcd05000000000465ab535100000000", "6a656363ac63536a", 0, 1802527845, "47baf350d78135ed42dcb858a005509f703818c446d93d26f5985277b39afd70"], + ["9ed32d290383a3ecfce908d9e977bccde06fa6f6486e1ac976f012df0dd25c5611e73972b200000000080051536500535365e4c824b95d30a997067a80bb49b72557ab199b6de8684e5b84ffd3246c51eebc79391b8402000000046a636353ffffffff2a9c8a47e95870edea12509817ae74b8e0eb6fc57d48c7519a1c12f5dda98eb50300000009ac51abab51536a5253a9c1a0a504de1866020000000009635253ab6aabac53530af40d010000000006006552515351486417040000000001ab80c3f50400000000036a655200000000", "51ac5253", 0, -1245784490, "1467ab789b34ffb7c1c6f3c6a60ef7b6d5eca83849c5f0765d7b6940d57807c2"], + ["70f6059902736f56a4296591bb3f3d4a52976aa3fc9827dedc32699d29978ac7348f1f12fa010000000163e97169622a8454824c41bc68fc30183027b3a4791a7b6562f664489a5523dbe3594ba94601000000056a00536aacffffffff04ea500105000000000151c5fb690300000000076352636a51005182bee600000000000552525351acd3b83e0200000000066a65ab63ac6ac3d6b14d", "00ac52ac5363", 0, 595504619, "4e55ca8169ffb904dccbcb6486edbff2d2714f1cd8ae74f246caa8fff1feecca"], + ["c0d7757e03970b116a4d0f906f1db9fa56b78d65965b30b79246af646885c9d9c3f026617703000000004522529cbdad30e50bb18b9f942e7c5de9c1ca30b1b1a01f8152300101b7c7511bccd93e0200000003005353ffffffff8c26b8289b7935bc9d3b0d690935e84873997956f17d09378ecccefe2e02c8d50300000004006a536affffffff0330b44903000000000152757d400000000000066a536a6a6a6394598a00000000000453ac00ac00000000", "6563", 2, 147961443, "a1850586c12c368071b9ccd117b154be8fb0330a08412e7edf6be1fb5383c371"], + ["ccc9d68c03adf249da52c948c670896f685736f633e7266576a3b33cdae227bb54d07e5299010000000300ab0096964f7ab0b68eeb4b955bb53005cc339532c550d5728f338566af1eda991b51d9f2b19c01000000075153536552536affffffff7b548e248f5d34fb384fbb0af40e9345baac27cdb10d632eca75686a9b83d44000000000066552656a0063ffffffff02efc111010000000004ab006a65a3191401000000000000000000", "0051655252", 2, 1598095345, "9bb7b9fb92f560ddc2c1f47e78d89c76414e637288e1410bf7041cc16b05301a"], + ["f2b7348d02e0616ad9e2904867e990faee270376b38714fbf57154175bb448a1acb45caf4f0300000000ec2c130c05b50ed369658ceffad3623b2684581f634f5714f55703a9bb31b7a616f58482010000000265abffffffff04ce2c6a0300000000035253abb869c0000000000004536a6a6aa2fe5e000000000004635353637cdb15050000000009abac6aacac6a65635100000000", "53ac63", 1, -126802225, "e32bf875ccc0f9458645b98cb0ee6b0d3b79aa95247c5e6746a8bddcd7c4c330"], + ["d4877d5a0117de1bd26885199917c681d48d46e5763cd1f55eb43afa5e4ab33f6517b1cac00300000009ab5200ab65ac6552ab78597e0201c376bf04000000000965ab516a656a53ac51c2e734af", "53", 0, -234047524, "9078eeda097422f6a3b60f9f01a41654bc1162c6bd65c6bcd78dbe49a8d92e4b"], + ["311ef42c03cc6958d797647abffcb895bb712e44ae7f714687a070928dfcb513949a60aa3a0300000005655300ac00cd4c36c885c22d5b2f5aa691d5aa7b3c218b74660a05fa2929de9be838b20fb08579a4030000000005ac5200656ab040e9f51d679dc03ce0e29f99d9c4148419898b4070b2deed2055e9ef5f37a44e87e4f100000000016345adc45803ecacbc040000000004636a00ac1fd50402000000000952636363655265acacabd5d2000000000007526a00516a005200000000", "ac655100525100", 2, 1843147335, "0feeb79992a4073b556bd4e628ff6039b510cadaeee278bc174f57aefa11e194"], + ["55ab00e60382a663b654c316fee688c767d5d0270715a228e3006516c65284f33b80ec514c02000000086a53ab53520052acffffffff3ef1ee116194cb3004ba5e3980f782f4e931b52a9fd1e42728f8196c930d04dc01000000036a0063ffffffffe036bf3188019ad6b7133d000fa3b013d13be4ca67e07745caf2b3f4d6ba544b020000000452636a51ffffffff02ade8120500000000016a34230e000000000009006a6300ac5251636500000000", "6363", 2, 993052767, "8cd4e36445d1ffb427b1cad73986432a9f2cf99b88835edd3378663e76701f8f"], + ["01f75d7b0450589a7d6f631fa0ec3d659d867ec390755d4de8fdabd7d84bab17af770987320000000008636a6a006a5251aba02e9108b3dbfde5fde8bfe50e641b8fdff62cd727404747e2bf79addd37bbfff24edbc502000000015223ad81f33900546d30df034d8acace2a8e26aba07cefc1e9a1001d03d967877c7b20269503000000056aab536351ffffffff22af3acd676cac77913f9f295399a98bf195064a5e22d60470487457d3bcb3400200000000e75a85530193e6050000000000045365abab00000000", "65", 2, 752818779, "6b747dd7ea91fde867d491e4c5776d855138e3f63ff800ed417e3e0ed120a13e"], + ["e55731c002d5d49d0bcc62cc926b4001dd7853b8a35ba989f8e883bed8a7017f54b3264d0c010000000665ab51ab5352ffffffff3464a2c1157451123d0fd4bfa0019aa2b707d374fae4e3e9f24eb277e054f0060300000005ac65535363ffffffff042e2f47010000000005ac6352ababa91d50050000000006655151ab53ac7d215903000000000700acac00ac6aabc1c17b020000000002536500000000", "656a", 0, -44655291, "93a8b8a7e960e8038fd3d2f17998d6cfb7c1f8cc8250821ec25156278600d18d"], + ["06139cf902e1b480a510bc6057e5f0cac0eecc8e51a5f8d99a3b1e847ec6b9e752e8de53ab0300000007516a516351ac6affffffff8db8ab104d5076d71e7e9f728df31dbb8a9b123fb2e651ed7fe3b1bbaf0b9f33010000000753ab6aabac656592582f8903196fb102000000000700516363630052d909860400000000040052ababfdeb28020000000004ab6553636a5ba7c8", "0053ab53", 1, -1705316128, "a2228b5cfe093de6c204e4c6b268cd8d9fff8998cf3fedb8df2a724a26d98c39"], + ["197f01b40186ca6bbaf0c99c61ae51f94009bac4b436d145b59f8def8da6b933db067fc5fb03000000016affffffff04438798030000000002ac525cd6f0000000000002525230d36e0200000000056aab6a6a65983ee1040000000006635152ab52ab5ff7c4d8", "", 0, 1670452338, "57daa5887e15ec4c99af7ad00b3f7bb5562c4ad885f9d7e2c8c919bcac6c4bbb"], + ["8c94ab0904331b879c115e11461e3812b3583857015c381904f772169745005ff1d890e4cd0300000009526aabab6a5263acac35c63239c1657f9f67f37611f710768cb410af977e8e4f70a982bea377775dfb45868b8f0000000001acffffffffa4636ccef2c416b1cc1168e6dd6c99b26fcf0851955858de795e30dc89ef673b02000000085265516351515165ffffffff3a58bc53297edae5e27cd3b8213dfe5fbcc39e71b4ced65b5d4ab0af54bdcd7a020000000151ffffffff034f6c4c020000000000442a0705000000000552ac5251ab2e7209020000000001ac00000000", "6a63ab51ab", 3, -1861391027, "717ae3170f87a6109213aed04f63a626a2c14add95156dcbb641c3ac8a134c29"], + ["48f9017d01b77e945683b3ff3e409d00b60418b553ad7a72fe7802bd6f1037738d4ce114f4000000000265538f95d43702fbf50f03000000000551006aab63b5f5590100000000060053006a536300000000", "6353ab52", 0, 496318719, "f54351b55d163bce830d5c0332f2d974c17b588c6fc286e9d39814750a2023ed"], + ["74af1f950127649dfbf6d3a5cc91bd733a93a56b27ee93e577f9dce548691e5c05cf4af0260300000007ab65ab0063ac00ffffffff0150c06e0000000000004c0349f4", "5200ac6353", 0, -417094535, "a7ea6ebced753d3a9de32efe8caa52dc260243c20db52916840fce45a8629969"], + ["93c329c10454418384b9e13859f93b2fed77b8d527b977d77aacc860c33b8e95d56d0f6ceb03000000096a52655200ab525351ffffffff39ce91ca91d51fae82df87e637659f0e6ed20a8f53c2077b4c3ea9d7731272f10100000009006365515252ac5252d4e8aad34a224b407e3c4992825da976a27ab86ea4fbec9c0ed206e12103850ef46d40e00300000004acacac52258cec22f17bed90058018fd14b0f83fbcd654df56470723d17a8a9d62a91bb4074551960300000009655200ac6a5253ac63ffffffff0206665b0000000000096a63abac6aab0051652aa975030000000009ab6aab52abab63526a05684427", "ab006aab63006a65", 1, 1966414297, "00ca1408d123efe277562c587c526b30ef665410b6a8d6b85ecc4f1af04f581b"], + ["d4a184d70203d359db387142aee710f0547c049200a041d5dca0e9eac15eb1f5191313cfd90300000009abac63ac63525300abebfd548125cd8ca29803bc724f2cf439f4fa4f21c05f1e5156042e1ca9a1db5e3e145b64010000000963ab00650051abab51ffffffff04eb14d8010000000001accdf7f90100000000066aacab5200653dfc2a050000000008630063515151acac7c829800000000000300526500000000", "005353ab", 0, -1514044206, "f0c3e27105ec46c865592f412aa0491edb0e5684fc09d2507b9ea9ded911e09f"], + ["a852a9d6018212510b6b6f7c9a5a6962f51f3272ec9b7535d5713bc82e3ee4535bf0af9d6602000000055152ab53635b8de87801757f7a050000000002ac5100000000", "63ac", 0, -1071811980, "96939aabf0c41aeeffcfc6e860cf8ebce038733c9a1e7d58d0003e3e26f5ad9e"], + ["9cba41b501b67ab718b7970c4c2efe859f35d227d150554a7c48d34434977b268fc18d47910200000004ac6500abe5b438b802dbe2030100000000025100c570560400000000015300000000", "ac", 0, 1681877711, "37268c0dbb6efe63228c77f8d8afdba06937b58884337f3cab2e54b0e534c9df"], + ["68dafe3401cb29bdcf7c9a0d06b00bb6371a0fa5e0754e4b4f08962db202373923ef78192f030000000852515251635152acffffffff035e505b00000000000451635365713c7e010000000008abac51ac6a536352e272b40200000000036a6a6500000000", "51530052", 0, 1562875078, "68ed22b877cd2c878e3b6985f2f6460f92bb0d8c72c0cd38a41aaa4646b603d1"], + ["54f1c9300393e361f65d9556aa1e3efd646443a5de7f0a88208d2dd42246aed9fb877779860000000000ffffffff8d01b50fbce9c4818ddf5dbfc68c110933a4c202ae1cb443561d2700434e5eda01000000095300526363ac6a6a65ffffffff0af80917b0e1fd01f8ef97d66be04c1e89911a2b015caf2c3c8c0248f7de70b102000000066565ab65acacf725f92304f6693100000000000800ac00ab635300ab0e73b60100000000056300656a51de51f0050000000005536a635265d5842602000000000600ab6352520000000000", "6565ac005265ac5100", 2, -176418614, "d8920771bf5ddd85b08f475aec1a5e933c2eda35e4c0075c589affdbaf0cc1cc"], + ["69b83315041ec6b52ad5c74afc90dcdbc68d750c9999f233464c8db24710261c4821894325000000000553ab52ac63e84ae81f64c418090cf792766e16458b440db76365614cb5611da22924e317dd4cb987e10200000007acac5151635163ffffffff63f1ab0917e58b683acf9c8f5ab0114c2fafb9b227c7368637252b86ec999be80200000009ab536a5165536363abffffffff4ca85d4c171597aac7f29140476b9dfd98f5eae7860880116c24ef6c036ede5600000000046565acabffffffff031bc6710100000000016507e2fe01000000000363526a52a2a204000000000000000000", "6a6551005153", 0, 663469004, "d16f226c485df997438d0213ea9b929bd60e4433aba36933c6068dc1a143d447"], + ["6756fed302a019d6b20db827e88f50c8e9a3efce5862b82ac9193326641b4e80420ed8c90502000000026365ffffffff85cc605bdd1e68fa63d21505e3c0752b797b965b0af95ca7d5ae9bf373fc13550000000000ffffffff041cfaef040000000007ab6a005352ac51e8723b02000000000465006563034ef503000000000653ac005100521e927003000000000300005200000000", "51635351536553", 1, 1496606554, "2ad853b92b82d1b4820814e7daedc09550b83045dab45b0858161c609d0dd98d"], + ["04a4ec2203655e264d9f033e67ffcf8522cc77ab7cce9d0fee0c87ce2aa3b1441e1980062f01000000046363656326c37f3a077e350a9616e31cdde7bc19093af48848f410bb8a7a35e24ca80d630413a1f00100000004ab51ac63ffffffff257b851fcd7d058926d9ef829b25a709bb37a9e220da5b180248095e3cc1b95f00000000066500ac6aac53ffffffff03188055040000000005535153ac52f9c3b302000000000057c62d04000000000063b1caa7", "6563535100ac63ab6a", 1, 460650857, "681eaa7c94ed3e57c5c545091499d3e91786797ecc9b2e0e9ae35319d294d771"], + ["b8785d83040860c2b369e377f2371b8311275fdfe0ed8a4ffd06ca5bac67c06c90710a54a200000000075251ab525365acffffffff8617040d622b26639868c9f729ae38a57014649c9507de2c655771c0b57a5e180100000003acabacffffffff19fb6f935a6bc1cf805a109aa851aca45cf66f2fec0288429083dfbd413b1a9e030000000700536565655252ea66888e70402eee45649afe82d6703c5bb883aa3a5458cc45f019a8b13927630d9051c803000000055200ac0063ab4d96dc014c0b0100000000000000000000", "53abab650000abac", 0, -155037963, "fb601212694e7a8539b70d8ae09e856e9e352d729e558cc0c1175f4803b05cc2"], + ["17c6ff3103037a9b5bb7102d4c1c7882729a1f7ad0c9f4ab03ca51b09d1b9afa6a70728a860200000007635252005265acffffffffe2c134a314b3af126d56b5f7604631085a71d10797edff30114af0365d7513410000000000ffffffff6990267c5cf5a2477c374c289eef220ac2e4f02a6d8f39a68783d882c59fb187000000000763536a0052ac6af0f4eac803d0138a0300000000036a6300de53fd030000000009006365006365656300a8a8ae0200000000035200ab4518b904", "ac", 2, 1928413138, "f39799a7fd5021171105dd23938678d985b6d2964b1bea5089f3e3d42eba1112"], + ["f1e6089901617b196469ed7bdac32bca9c2468bbbe0169c3d53278b78fe10bef89f8d334920300000004636351525050554c04106b040500000000025265384e4303000000000651ac535151651748ee010000000000013c85050000000002655100000000", "656a51636a", 0, 1025105391, "1557b140c82a8a008a02940c432fcd308f6890fcddb83d8a7989799ef7856d8a"], + ["cad4df1b04e093a2ea7f870f393a5668a3471e83a547afb87110db7b013319ddf8ceba5d000200000003ab5365e6a448f2d87ff752992eeb0ba4498a2cf51c779a2571e26bdc02d7eb026a0977f365ed1a0200000007526a656a656aacf26824730e9b10bfda8a411c8084d3bb4aa9095811ceb4eb77d036c7a7e72755a137e9700000000005526a6a53514898570d98372f3b951539e6f21cfee81131922a16ad3978f51512e7d3c142de6cf4788001000000066a52ac005165ffffffff0355aa1f010000000008ab0051ac6353ac51e74426030000000007ab656aabac525217c2ff02000000000152be89d838", "ab", 3, -714885673, "a4522fd934aff87ee45959a88ab2063b2c5109788dc3bb6c2b108f96bc730e7e"], + ["14c95b3701ed87c3faa01d56d4221f80df4d87a4aab21e6fcc105fa333b02c960563ce2054030000000752ababac6a53513b9068a701374d3a0100000000076365520000655300000000", "6a65", 0, -167338770, "f391201f82115c4dad0af53acb2beb41714e2ad1b16ac8e4486777b1fa7be402"], + ["669821df0247eabaf38989a13dce47d95209ca18025eeda5c43ae2f2b1d61ada8c8eda85300000000008006a5163655365acffffffff44507e129bab925c3c1282beb3ba76ca30715caf807ac5b0502d16bdb1fc9329020000000752516aacab5153ffffffff032304310200000000086552ab63656aacac823e76050000000005006a535100eec24a0500000000075353abacab6a6500000000", "ab5263", 0, 1459488997, "1ea3e206a44babe3c73240122c77766cc307f274eb3e6e4ca3e7b6d77bff640a"], + ["a506805f041c101a77658451ad1d0ce5ecaba337d4a9a0ef94605bea2480276e37f842976000000000035152002418f83d29a82967d51b253f6dc7e0383494fa54d0e562c6922c2f7f5611cf8b2e7234290300000009526a536a6aab0000ab04f525bf50834482c6e16b24e7c692254c90af0a32fc16f4ffb7c431bfb584d0a9220d240100000005ab6aacac51f4d590f596075e82467e603ff4d39e7dd45c6da4237b71f1f87bc12782fe5136e225f08e030000000851ab0000abababac0ddb59db010a8030000000000007656500510052ab00000000", "52536500", 0, -374594361, "18b1ad1acd03da82e27d3768367ec7fe78ff10bcb83846952fd01c66c1278dce"], + ["f6de3a1303c42928614b2054423fa2623a7f6c2b4b54a44bca453d627e89e8206175426a3203000000036a6a6397b99ed36e35d1142f5634f804d2fcceb39ad922637664a618c986e87f0d18fccac06cd00000000005006563ab51ffffffff9ab9cd351d40bb3c4af1e47743332ae08ccb554595a2950a9e613bddac1437b70100000009516a636a5353636a5166f088690331e6c70500000000050000516a65d8afb5000000000001009ee3370300000000096a00636363acab656300000000", "635165", 2, -2012388278, "63284c9e3658067bf9e35eb4a7333099873d3286b5c704ddef67dbd78e979ec6"], + ["1248987203a12818a74c2b50258d732bb798de6e3e74f3f4ea2d0014fa351192e57df1400b0200000007ac5351ab6363ab4bc545af38303851db8dd1fa76b4da0078d193ba043bb85a49262428df333334ac2cb0fc030000000451acac65ffffffffebb8bff29ea0ee367068c6651a093433a9ac88886489c6b29fa8ff8fc52652b400000000066a6a516a65acbb1037a603fa924102000000000086c863030000000002635182e38c0200000000090053526a6a6a516a6a00000000", "5300636aacac", 0, 858977273, "00a6991ff378addc1dd150867d731ee217750f85200793d2616a6e3e7ea43c6b"], + ["6397a0f20248d7fed9442a160ce7294c8d78147d61fe4bec505dbfcc6b2c92dad4fa8834ae0100000000035a009f04a4f65df7631c21464675959e2f05224bc629a5add227f57dc12974748dc6b001000000076a536a53530065ffffffff043bd7ba000000000000d3d6d3050000000006ac00ab63acab28d7fa020000000001ab2dedba050000000008006365ab5300526a7b6d018f", "51", 0, 541981262, "65fe57157adb2be545a308860b1ca0941f2c8b8c233ceeb7117e183938a5f5b2"], + ["5ea5211d04ef103baf7795ff4c5438792354528b9b1c9b453d8e9f890cefd9226f19aa11c10200000003005251ffffffff8a6d30d11a7c338f10de75443b7ff48de83311b83ddf3367f3ad2963574898870000000005635251ac631ef1a786a1feaa023c340a0482e0862f78bf93834e7ba38d986cc9c976a355aa47b90bb90100000001acffffffffcb30766432462faaac0caaf1c88aaa39a056dfa074e3e55999935cbe428f3e37020000000042a1f8f502dac5ca03000000000552ac63ac539d99a1000000000001ab00000000", "00636a51", 3, -615594795, "f61a3f8f9d43a182509d5607ea5682498e8d72f5b716551c2dc4ddd00578f686"], + ["3995a4bc04f2d99438cae74d331141423a064f0bf94e27c0a554001e49d4a68e39501fa57203000000025153ffffffff8f10648ce8ea252fbf46f442cb9c332181c197ab5e335a36908c7d150bcb40e602000000055365ab510057bdc171d7d79cae09ee71892265c024d078fa3c8b91a2ba85ddecb11ead14d6eb18a2b5000000000651ab5352acacf91df44f96b300e33011d77628c73de5961d8b8f7d7822441406c327a3f960e9b8a891e90100000003636a6a7edae9ce02da663c0300000000046a6aab52d8c611030000000007536aab526a52ac00000000", "", 3, 952048473, "d831bb23f635fce6b61c80634f4d7e3f11a0b932d36564a3b46ca52986a8cc75"], + ["59acb4bc0123b01f124d32a05d03174a9601a4245644e87066da8a8e0c8ef1b6f0dc4843ef01000000086563006a6553ac637821f18a03e750e40500000000026363da9f2000000000000565000053ac46d3c6000000000006536aac656a00a839f1e8", "ac65", 0, -1054507678, "e9d9d6afc05eab391ed16d5b6657fd75026091b9fd150b820ce184f8c9f6a50c"], + ["82215bdc03d0abfa3cf8785257c5e13f0c588a0c9d4992a11335db72162d71b23c0e8c80b602000000076aac6551ab5251ffffffff0b44ec1180cfe4591455173b6d8b6d9d9d2fb5882e955ad1c4227e0a1e9dc223030000000563abab6a65ffffffffa32276e2334473755170812e00efdf6e7e0932d52762f6f62a4d0e414bcf313403000000095351ac005263acac631d46a9340104f1070100000000055200abab5200000000", "6aac", 1, -1586094121, "7acb204cfa6f6e3dacff0ca1a4af3142f20f08cc614ecd87ecbded7744dcda5b"], + ["02d86a8501d8e3db0deb4c33565c2328f5765fcb7741c31e164b990754779d0e5a82007b07020000000751636a51656a52dcdce29204e1531601000000000965ac6a6500ac515363e193ea040000000002acabb3c04b0300000000076565ac00ac5365bd3e9702000000000400ac0065b2dcd423", "52abac6565ac53", 0, -967548034, "b762b06aac11b6b0937657ce6346c2952957317496e105781d064560ad5f6fb6"], + ["35e994ee010d32cd7533eb2319c9a150647b26bf05bc3098afa155f2c09a09a146b0dc47820200000003acac63fba58619045046a104000000000100d9e771020000000004ab6a536560e958050000000002acabf2d3c90500000000076a006352535152288ab5da", "51ab", 0, 1200550009, "49911786bf46666ab763db2ad1ed834e2cb09f355e28c645a82344da15e4c5d4"], + ["afdab54c016c2dbc5cfb2532597ad16254744fb6ba9f0ed66187df4288fc138df72a4bcd760100000000ffffffff037e389a000000000006ac655200510092ce4e0000000000045152650001949503000000000000000000", "51ab5365516a", 0, 571955401, "8492fcc0e6375dbeea359c03cdba936656a6a97381353b3439292f37d6f42b54"], + ["978b93cc0192d822eddd31f62cf188faf36c0838f2ac63fcb282688424f11fa4c8c66962a303000000066a00536a5351ffffffff0457352700000000000263ac7ce7c20200000000046a650053433de8040000000004005363ab4f91d80000000000095300526a6a6353abac0be3eea6", "52ac0065ab", 0, -164208039, "920b6be0783b97a0a185bac3adb137b1c1c2df54def1d3f03d04dec4e909b032"], + ["5989bd9001fea3d6083b3e679703e1ac35c2725604aa8626f78ab98333f929b474b67e063c000000000152cae3985a02cefe3a020000000001009e856905000000000500005100ab00000000", "ac52", 0, -1162574502, "82e423d6655243b5983d0f0d45b3909d2f808799975d02c0fd54c376478bb41c"], + ["3fd6f65903a56d01da719cd353b2aa2ca2d52f2d75dd78caff88dfc458beb31d04cac746430000000006005152ab5300fffffffff4812401e9f00165c1873da2219a70ce9986eb1d4af2280e4382cd9756fdf894000000000553656300526b6227f15f24503506cdc7b4efa6879b4a19697f5e37ce174bbcfce4cc9150e720e111fc010000000965ab00655300000000ffffffff0158d81a010000000006ab5165656a51e45b26a0", "00", 0, -1134678535, "f389cb249cc0300d6bad5300974a7b609ae6f16f36237831d9bc74580b5fcb85"], + ["3793027204ddefa1628188f8374214a8c196e9bbeccc25818549aa9cfe3f60f9f2c767f6440200000006516a000065acbc912a2638ddf7ebb547387ff2ba648806d3955d19c22bf0176dd8dc4e14116c9c26e237010000000465656a51ffffffff9d53191bfc1cde20deca33001992953bc0269b5621d95f2e34de24fb3de1a042010000000352ab00ba092106bb73b325ec793e968a1bd20d21605a78d46d4b1bdce4e9b98d4673213e6c5cb60000000006ab00005252ac56e274b604bd68fb020000000004acac5100f1c96b0100000000036a5265a6ef420000000000096a00526aac5365ab0055b37a0400000000016a00000000", "6a", 2, 1802669439, "6259f7c353b8548ccc39b1fd0f015486188d181d49fa224f5f1fe46b4d5250c3"], + ["c7d7bbe0019f7c10a22f5aa5815374fff16703696b55d27037096d1fab43abc4541c978be80000000000d0b4c22102abf7790000000000004534040000000000086551515353526365eb89660d", "526565516353", 0, 46606811, "4591327fea57d32ee19b72119f2f73a34290b41f6207588c74792c0569f16836"], + ["b5c9009a02df15e49f591fed652dbbccce498a594988c7d9b4045bdfe0b0180950582d59c20300000004ac6a0053ffffffffe565912df3f3655e1321cefa14b341c1dbbf7b0f066a2e5a1cf20436d90f08e700000000076a6563535365abc1c2560403378930030000000009ab5151535353536a6ac5957b050000000001abd8ff90030000000009636a6351006a52ac53bfa0ba15", "", 0, 338266365, "73fc300c8294aec76e463cba658a29935abf8d511b60a3d7e360fa85a50ca0e5"], + ["b2254c74035ac6ca8842af30bbade26ffdd78aa868e08e11d18aa53dfea40ba377cba8ec2702000000050053515251fffffffff6aa8141f8edcadc7943d0960b9e5eb8942c188a487007f238dbcbc8633379820200000009655265006351ac5200fe70ecc91d4ef8f1754dac3058cb600dfb79cb4191ce24c59daed6de90148e2b9d3b473001000000026a00c9b809ad01aeea19010000000005636351ab6a18935952", "ab6352ab516a", 0, -1799524641, "344530efa102e0f24392cb684dcb7910514cd89f264a408bb60bf523bae879c2"], + ["98388dd4044342386904b76650e06e019eef90c466f218f659bdf3d5bf95387e830f17d99b020000000363ac6a6a48545d2d971cb1b8a5706c5062fc0aef85be4da37f927000fdf05febb5a5c618dc9aa70300000000ffffffff265833906a78be6518ff59e42035f5629a3460de2af7d3de7c8eebed9b3922c9010000000165ffffffffe450edd4f30582ff745274b64175e5483df7f2f210c7a57874889bb4e4e5c54501000000056a6553656affffffff02a2445103000000000700536a52656a51d24ded000000000003630053e6cfa983", "0051", 1, 679860686, "6f8dfd0aab5f71b1af67c48232a43e1159f31ce4fc92b3aeb69e3d07ece39d84"], + ["7ce9b6f203db504d0cf94acd9ee37e441acee2be1f44912922bac234cbc02f69eed9f7040002000000016affffffff24aba01ea18595d97839a10e918e30a71efbf259b30453fee4c566b168cac4660300000008526a53536300ac63ffffffff24490dab28741cf07d62dd807b925700b50fd569874dfecf09834fd93d3b4e3c03000000056351526a52ffffffff04c8b7b0000000000009655263ac6353ac6a65f3a120030000000005000052ac65832918020000000006ac6a6a00635130c8c30300000000056a51535265449832fc", "6500", 2, -604397458, "35bc84e4a9077b3501a2312f5a9f65cae6e5c5d009823503ab44f2a26f8dbc38"], + ["9b679877031876dfb3bfa0f6d8010336fdb488dd423d42405cea3d8cd9eb16b4c0badd785403000000055252655100ffffffff7b1c88b7490ddab1d2351dddb6742a4f6349293e3f39ddadca0495dd388ddf99020000000153ffffffff8c4bbdd8efa4fb59aa82cecc3962641f402d25ed7cd637870195a6a3bf5d59c0030000000800abac6a53516500ffffffff03877ddd0400000000076a5251516aab65438a2204000000000093780d0200000000056aab6aacac1a0e4b0d", "ac65", 0, 1255088477, "4759071bfd5cd408c4530673db8be5a925db581f121f6176161b35dd2aa0b0d7"], + ["ec22bab8048f90148be55b0e0529aa03d482f967ad0cbf80a09eabc5261ad5509d4a3aaaa702000000003100da2d44f358ea2b8eb0a965129718367cb4838f2bf92a3ace737efb845724df30b947020000000963ab535353636a536affffffff0712debe56ca423e639f37fc3b3d0a5c0d7bdbfba6e0558f952ad3dc3d730a84000000000865abababab536a00ffffffffe34d79de259a697ddeebea3a1337990155c89c57ef7255bb3bbe74fe9a5da6b40100000000f11c174303403ab7010000000005ac526aabac85aeb204000000000048b46900000000000351536300000000", "51ac5163510051", 0, -1140095650, "87440f1d3457d5d3ed0e37b618ec2ec49d605716840da292f27eaea4ada0899e"], + ["408d997501a3771c1538ba8fc75637f3fc0c4a9d7698265c266ccc743e0aa472480d6926fa01000000046a53510064086fda027f055f0300000000003508620400000000046a53515300000000", "63635251abab51", 0, -443012890, "5431a8bcb9be8ae63d7e0872d644639ca69a9cbb6240e83ce09e9159111721fa"], + ["71cd681b02136e8ddcae73fecd1b7e8c195296c150cd243e56eb1b9497f8da495d380ff58b0100000006636565ac6a6af438981250fcf25f653800e4dfe5f69aca33f5796329e6997630fb4235ade809e503a9be0000000000ffffffff04bacfb604000000000653ab52ac656527abb3020000000008526a65536a53ab00ebd1d204000000000552656363acf6a1e005000000000251636f0a425f", "6552", 0, 1735093500, "0ed6f80e3b8f20b6bdd09fda22c7ad0d161e181b4e1c9af165bb703a87780cfc"], + ["f88a5f87039c5e5944d6d210e64be51ef31e2cf6d54e31e106df4426468a587c4b3d40079b02000000025353ffffffff3a17edb73171baa66e606faa7fb502a803d4153e6dc9baf6dfe6de7940f523d102000000085163006aabab5152eb9a4ead5a768e870469f9b6f8185f98b2c0fb455247b13a001c70cf7f90aa6e0441095f0100000006ab6565acab6affffffff02e54f39010000000003636353cdc63403000000000000000000", "ab52630065", 0, 2107469775, "1d99adbdc8631c0d3aeb26e5f28fcdec34c6a4acb9fc277456b5f19dc15e6e3c"], + ["34d6820204d2d1d322eb6eca8df53729963109bfcf66ce518f5e9482f10555370a0e57a3c3010000000165ffffffff1c5f9f10bd575c8814a51700989097be89d77c105bedbe2c64e115d254c4c7b4010000000851acab5251ac0063ffffffff67cd134ad49712b3ecadd75b8faf46b9b87e7b711ec7f2b0e7b8e0e10e4e42bc0000000004abab65acffffffff88eeb974befe6c441eaaf3f28ab90a912c5ef91e7380d3d3b537b39925ad9ef3000000000751ac516a65ac6affffffff0365091b0300000000035351ac629d87000000000003516a632d38e803000000000353650062394d23", "005251", 3, 876150232, "2232c9cfa50fdae41964c2d5d2cfbb89829e229bb4a0a97353def6e1b1119b97"], + ["d94d73f801a075cbf5b3abc8fead3930806d58c9d7c979141b0e8b47157de887e95c5ab2a6020000000751515253006a53ffffffff01f9ea5002000000000500ac6500526b0ae138", "655165656a53ac", 0, 1899049599, "fc553935144c843207617530229bf84390ec8a0c17df73d8dac65060ae202f75"], + ["44507aed038d4268f96590dc8c43064d278f72f2ba96d9ed7f11efebf98f05d12abd5232c701000000036553ace76292c831056dbfd874c83ae39eef357552fba37e5d2a434326969dca9e65e2f2851f720000000000a7912bbb619b25a24c9565a1bdbfa3b71d230cc30eb80c9e4589fbb0c2511a03d32b1468030000000453006a65ffffffff03b562c400000000000163dd7ef404000000000165ff8dca03000000000865ac5200ac51536374aeddb2", "ac636351", 1, -970112048, "8f5d014b62fa904b829440787e9be99c0db7c70f87e652fd7d9ba540c76a6b7c"], + ["1ed44b5903c96b5bb696322e88bf00b0551129bc436fbd19f489a2ce18517bdc49d47f498a0000000001636514d2ec5536ab8286f04df77c3441645b89316f128fea75272be9b3bffa52663f4a6c990000000005000065635106071dad096b973a62ca4b0451ee5a4af6af0a534ae3181bb86fe31870360da67efc99fd0200000004ac000053a1232be8027df04a010000000006535300ab6aac010ea6030000000009636352ab536551515300000000", "65", 2, -558055059, "c7f10083358ef2c7e500c68e39cdef74117ed68648d3a65605394c3fdbfcadd1"], + ["c42094cb03739a8b5174549f4bd92bb44c9483037fe4d1a1bdd7e64413b1fbe90b42fb698802000000070053536300abaccf1b687876e2e9ce04f3b19364d023926d7cee4ac2aa2d17d3a19c76f7e10096f6fdb4390200000001003a91f13ad53d40d3406ca8fd89e51d287953c018a1794487da929ad02d30b6be9fe1b7210100000003636363ffffffff0188ed130400000000016300000000", "65ab53515163650052", 1, -104936068, "b1efb6397b8e93c61da144cff03206f52f825ff6e552c6c0370fd25c6a160b88"], + ["651b76e7038401b3840f04151c3dff1a499f152cfe31a6874c2c5fa379f54d5c8d3332da8e00000000026500ffffffff268a090be3efef809f72b5fea98725da6b76e76f4376d35700dedb267877cb9c030000000553ac526a00ffffffff99a09b6944f97d3902cfca696d77de29f1bbb77887ad7df4e3e09743eab364660100000002ac651ccc3e6d0499ff11020000000004ab635200b9cc96040000000007ab0052516a0051d361520400000000096a6a636a5352ac636301dd0c0000000000086552526352ac006500000000", "536a", 1, -1916306350, "fafe236f359e00b9447e157b0aeb7e356158a0944d02e837b90a36c0f783d019"], + ["d809c36004a9eb11747bf1a17877f0c00e3ec21eb5a5b0419aa0fa2bbb601d185461dc9ff50100000005510063526affffffffefd1866b4d0c56c1dab50e183a09e5c49d43083492265ae5c7c53ee4b6eb60f40300000009005365516300ab52532d6d8a1f85e4fab45b4e9cf851e8bea213981d5f188ff326abb8a5d4b2214e9b8c4098c500000000046a0065ab41ec73cc9633dd1646d49a47295e97cd1a297074c5af6a0b0b2eba05563009127e86821503000000025351ffffffff0171a5d5050000000002ab537f2c6e2c", "65656a6aac53ab6351", 0, 1887760587, "2c198a34e44216a8851cbc3f119e713d4929c16f1313b270d2856a1e75412bb8"], + ["6656c4a604173f4aa20cfca6e78eb12d0c6ea49a14613a2d4212077dd954fb4b2f716a8a9b01000000016affffffff6e55e9b39481e40796f00e6af8f6938ddfa9be4c166133551be6e5ac632163ab0200000007006aabac51656597fffa2ca735cf901d12b13c0df04eef459a66365185181a2ef17e0eb0ad5c7b74d8166401000000076a636aab6363acbb594c7affc0bc236234eae66cc6f8ad98d5619236d67572f7974d68c42882dc420e407e00000000066a6353635263ffffffff03327f1e04000000000565ac6a6553eca52f010000000005536363525145e01c010000000008ab52abab53abac5100000000", "00", 0, -1110443063, "e963e7d43ec25eb76e1e6bb5dfe41fe8967a4442189bb58fef65b3a9d20f6dc6"], + ["a367df9f031b42209900c8b8d0457df17c1b00c2c024887f77b93e706b5418c08035ff99d0020000000153ffffffff3c68ea232c3ac5c480b80317afa47a1743c042d1edd72d57c8e7edee8e7bee9803000000086aac656a51ac516affffffff4209abf29ffefe898bc349e16386ed4d5b90ba43e8813a26ee8b91c413dacbcf0200000002530097c8986e03fd67be02000000000200ab61fa5b030000000009525352ac515165ab51a0a5ea05000000000952ac520000ac526353a78df8fe", "65006a6a53516aab51", 1, -1070973963, "175774c5fd28b46df53eb73744aafd5e7bb97b5dfdf5d31f65b7052751c8fb7e"], + ["45cbdbe701eb963091e9a54e19d9db4c9c5d40532d19fcfe4484c27de7fe80d9f7c14ad0420100000007ac6553ab525351ffffffff045accd20400000000045352515145a4e9010000000005516a0053aca6dda20300000000046a00635369624b04000000000353006a00000000", "ab0063ab63", 0, 928333305, "28395c063389a393b7937705512c57504d6ffb26fe5551f1d0fc059356d92f4a"], + ["c6ca9ab201634938649d0f5586973db47848803cec532aa621173765003584169b42ea82690200000001acffffffff01f16bf2020000000004526aac5200000000", "52ab65acac5165536a", 0, 1916832993, "b8f0e859481b20ee0ff8fb3342abff4217b3116336c9642b00c316970fc12e4c"], + ["21a489ba01c391469494794aa0edf996d05795ec28aaef81c8bb92abf769a1c2b06a4cc98c0300000000521ca4d801a4318c000000000005636351ac5129e462db", "5100", 0, 1732957013, "7ecfb47cda71c4bfdc1b9cb5a7b5d8080aa97e361262069f846d3696688d4754"], + ["1f7a57fb04abf5b01134371676437ac5ffc9e56733fa86eff618162e19ce1f87d6c272fbd302000000085263ab6a6a00ab527df21ddf680de4df4d991511df204b69f985a2bfbb0527806473c4447a8688015f240b33000000000800ac51635252ac65ffffffffe9c11d5391c8be7f1b82a27f022758a3080a9a559f7c2af32bf7fc2792f97e2702000000036500acffffffffca67ebd6c72bf7f9db168f321ac68ae7ca241c176ca1d00e24481a1e8d795830010000000600ac6a525200d097b73902a83eae010000000001ac0a58190500000000040053650000000000", "00", 0, 1156518382, "329b2a52f863ae3addc1fa92423b45c688407365543c952527e6d9a4fc4dfbd0"], + ["910c6ba4046deb6eafd18b79fbe95e833a53e0f7bbcfef2912895af6ab4119c11face8004e0000000000ffffffff67a872ed2231855572a074338d8cee8cb63affc05e7cdb238c053182414363e90200000006656300635353506243247176f3b667205e5bd480e4cf6582928a2de80b69bf3e064a32322a5156d3964b01000000046551516521f76e8b212e0ffabed7e93aac09a0d6d3eb65ca5ead8ea7af0ba7bbd8c30c35ac6b29240300000001657d4ed94601f1b7d3000000000001ab00000000", "6563005251536a6a53", 1, 1232916929, "05234d0dfdbde6edebb9c793a6d1a8d4a91671dcc66aeea26b1804ac98cde507"], + ["5cd6019802ed11b14ac57941ebd620622807019e7da97643e4c576e6263fe9dd63a1f29de2000000000753536a53655263ffffffffe4d9a37f00360ace660b70e00857b50c1fc6b6b384766951f47b383dbdb3d47a000000000651ab5351ac00ffffffff03290b3c0000000000004663ab020000000007ac63abac5151ac39a1ef0100000000076a51ab6a63ac53969474f7", "00", 0, -674352181, "6f8b1e664bfcd3f1eb277687d9888938737a7b4b1d24216c89570f29002c7db9"], + ["a25c176f049c3005297672372c7c3be1ce2179661b61a03aac92f11e716ea3f4de738f276902000000066552ab63ac53d4260355cf119ca1258a656551108c245bf27b745edda82302e67a08a8ecc5b1d8e38bbd0300000000bcdf52d7c7a1f574428eeedf608ad1e1c6951292d1f3aad763a0f133a0a4fc0fbac2c59f030000000865acac00ab0065637d74454a1c7592d6c977b3501a9a813f0c76f01205955524a291f5084c09e5197c28bff30100000001abffffffff0410c9b0010000000004636aab6a98a60d000000000007ac52ab51510051c59dea030000000005655165abab018ce0000000000008ab5100526353006500000000", "6aac6a", 3, -817496512, "a0a35ca2ed5d94d90e38bf3cd1db266d1f1c49bb3e68279d51c25ed364368f72"], + ["0dd38fc903d8569288d4ca9c30c65e512f1f9ed5ddf46d0798bcde22ec0408360823696a22010000000965ac6a52516a00536affffffff79397e5ed84a96b8f6e2be229de116f714fa1941dafb192160e201db546d74890300000004ab6aac6a70d2c88e22d0db334e1b0fb121eff6ab3392c6a0cc3837c696b8af3d5962568777f3545e020000000763655300acab63ffffffff035f5abf04000000000451ab6a6a2daa100400000000026551ebeb3604000000000652635100acacb748f491", "acac6551ac63536a", 2, -734375057, "9139a7fe59352100b8379d26ca8f658f5eb84323fecd92695fe9b2e967627164"], + ["fa594856044c50e84e3092867b126f7d8c4a3b1eb3bdfd50cb6ebadf12929ffe445bea496e0000000003abab6affffffffbc00367975045f74fed80e6fc15b3ed917acb7fcb5d01a27b311e227617e3e680200000005ab6a52ab637ead0ffbb95b535e9b3b60ffaeaa90ef69f6c1c9c04b37fdeae35a742d0e29b0989956c8020000000865ac655252ab52acffffffff9bd439eb4ae9341964085e149c99b0b5df8ce9f05160506e0f233a62c2c22672020000000100876d75d9015c25fa04000000000765ac5300abacacb2c5f292", "535265656aab65acab", 2, 1653221069, "ee6afcfaf900aa1700930d90c0eb05c55a2b93dce0648e48bb7cb2e385800c57"], + ["92c6dc9004859dd0890589c266d899538a416e2bc2269efacf3857440bd906a78652d5490c00000000002f6b3ea1143a376c4ab4ac3aaeb8b8d8da791cb06481848a75914877a859ef02b38aa39401000000096365acac5153526a63e573738d4a104581688f198489dece0f188ba299d563559b0a04c967f28a14bbb5b7676c0100000001acb2d575b8f81338e1b6fbed6d7790c2eb76841a8ca5d84afba1727350de40d1ac3e2dbc51020000000663ab51ab65005f6c5990043542bb0500000000025152f74a210500000000056a5200abac1cb0d0050000000005abac53ac0034e5100000000000045153ac00264b5d38", "6a65", 3, -215018267, "9483193c6ffa72285aa667327e859568a370a9979d64d7f7e9a322776a537add"], + ["ce37604703d56c37d0c5830958afe5469afd664668bcc02a36d6a1cd7eaacce5a6dce8b1fa0200000000ffffffff403fae4c3613c98288c53e3b3ad1a7296594a289f3fa548dd4bf4ef3aa0058870200000001511c335e39de46999f55d2b77b0f4e888c02d6c97767d2fa91da8eb4460eb83e86b80d4a8e0200000002ac533cb739a9044abb9c030000000005acac526365ba52be050000000006ab536300ac6340e04b02000000000265538efc0901000000000965ab6552ab516a6a00c7d85489", "", 1, 1766785894, "5dbc9277c371676be63c41c906267b269e2d2b772ad28c13368aa330e650f9dd"], + ["e8533f920105bea297ea302932897b3b07cc8f23a2d9351bd538d98bd546268ce6f68f7345000000000363526ab9df2aeb039ffd410400000000036363ab3cdc5a0500000000086363ac00006363ab8d1efd01000000000058d9cfc7", "656a52ac", 0, -1169664959, "f7352d5720f924ef4d1bd99368661de7154feec300cce3f902a95c9a7f3e2c41"], + ["261c643204058c8eed8c3c60baa1742f25f6b6e4d3dd623bd406bc5b2f5b8e8bfbc7b5901e0300000007520051ab636a534b9a93e6bf86845c44896ba1b010540e7c953b79316881c399084c5be9abfb126a3c03bc030000000663ab6a6a6352edc5f65df0a8ba96c243933c8e829538aeb932cef2914ed90cd07a1076e5a78cc27adf850100000003abab52ffffffffa94bab100e962b924a173a2ed143a64188979b1e0b930fcf4c2708903c0e7a870000000004acab5365ffffffff0215fee1010000000002515136fae3030000000006ab536a00ac65be5727f8", "6a63ab53", 1, -189908014, "555e4cf15b0853db061266a29a557fbaccc16d8237a3c674f918e7f5ec0ce351"], + ["7c6b09fc0285c6479f44fd3c11601562e8e69de9e66a6718deb7d62ae8e544aeb33881f34403000000086553006552655352ffffffff4fd92dee6b854d1e0c2c727a2592dd667019b8c5187a10dbd036de3e7fb702b701000000086a00536a0063ac539a1daf9404e570b7000000000002acac803c2c030000000008ac516353ac526a52b1a126030000000006ab5363ab00537cf61a0200000000065165536a63632a71fef5", "00ac5352656a", 1, 1044269417, "8f40c5a90d8c3ba0344a64a5cc4ca67a2003d25bf229d39de2b121f3726dcbb3"], + ["7ee484390169e994fe170881544736138f45132f7e551a0d19f6377c5f191f25aa88e91dd301000000026a65ffffffff01deae61000000000006536a006a656500000000", "52006aabacac65ac00", 0, -909356216, "586827534d361ecf96de4d2d7fbe554ee7227433cb83bdff56c9ccc7da30231a"], + ["f5444268039e92d23dd6c1ce8c8bf94ef51f91155f8005520513622765054bc568a93181ac0300000004655200519a2239acde3a32b3377c647e06b8ffa128746ffc481b59c3d5d2c6352ede4f50afd8c5a402000000036352acd3ee33eb4ec3e5d9159e4879d3febee2d99420750f64813eb00d2e122af1200b83ca67620200000007abacab6a53ac51efe08fb604d38185010000000009abac51525153ab6aab5db07005000000000200512db912030000000009abab5252655163006a6474f7020000000006516aab52516a00000000", "ab525151ac5151", 0, 125082566, "c5fbaf40dfae16f1cbb12fae0f7bf6b193aac85a14cf55d68b5aa44df3a89be6"], + ["e1a3b8d8043b06d638465e973f39a7cadc306a447b106330b1db1842152ba6ad24fa04ad9b01000000016a104216a5e52adbcf17412c09a02b43e460de742947f1ee4b37504076ed73e0d24d9ef4630000000008ac6a006a63006553ffffffff342c32c0a2159e28dd2894bbfddcd65ca91f07eaba661e1ce3ad48098d52342e000000000665636a63ac52e73a7f8d92b2941da62ee3ad1717dc0aac7d918e4c6e86f1b1c69b091ee01a13663e93130000000000965b744002dc3952000000000005acab656a00bc7eba01000000000365ac00c6d2780d", "52", 0, 81352825, "9ddcf9e945d40fbc220218ac89f004523f26f7ffe40ebaf6585481009cfe8144"], + ["11198b4103a38a4bfdac83bb642d122af0bd22e0cdf04ee6ed2b2cc4e9494c66363ae4ae820300000000ffffffff7ab7b3dd58bb8666b672ae4e2a6146ec6141fd5796f55124af988dae24a609e70000000008ac65ac63005363acffffffff7f221191e2ee5013d45e7659f2e179b1bb89b9943eb256a7330f77f87dc52ec00200000009ac51ab635252536a6affffffff02e2b9fa0300000000036353520a918b010000000009ac535200530063abac00000000", "", 1, -1699648695, "fb6eeef648a0194c2c9a05b209f23e9a1717d29cc00e301e94c0003082c3dde9"], + ["476a5f3902f79f815feb30635f6fcc38f7811df2fb378d61e20bdc5a32550a0a1a15ec5fdf0300000000c212027e41f4cff6616d56d2f8ae82ec72d671f9edbb3892e9047ea3e9f6806cf6bd43e90200000000ffffffff013b8b21020000000003abababa68bf7aa", "63", 1, 839489022, "8724c688f3ab426ee51965fd00a983b08fb2c75de3ae74c79a8ec14a43670fc6"], + ["d729ae610155d1f942c9a59e59c415ea543f6be22e45c02877252ffd7bbd5bb8f24042430502000000096352656a5265656aacffffffff02f7aadb0500000000000c2c33030000000005526aab525300000000", "ac006552ac635165", 0, -372383150, "213074c12db12d79018e15ac01cead96599f8bc2bac43aa78dbead0dcc4cabc4"], + ["cc50fb7e0345d249ceba5ce1babd50fef7bf4f9ad0a148f71a137bc99ad57cba6ccf2043310200000008006a516a6aab6352ffffffff141555a8e186f0d6e4a2645c18b1758f0438015aa623516a9af55df26f89a837030000000451006a53ffffffff5aebb5145bd0ad1cd26a2f4e71546c3a0d27a82a9f5456e4e810e1f2406c4029010000000163ffffffff04df6c280000000000056553516351146cf3030000000006635100516563992945040000000003acabac9ddb66030000000009ab53ab000051ac0065ed2687b5", "526353", 2, 1086142546, "23c0a05bd3638464336637da8efbe044e70fd37377396f058381c19262a95530"], + ["cc0f1adb028e24de3844a3cff62037e18c39fda08b9cb6bd197433caaa1ff1e0dd65f3e65001000000026551ffffffffafb1939775b27fa98312fb7b89e2ea1133d19f1842b39e32539df78c0646b012010000000852ac52ac6552526375e6a92301e40ac8010000000008abab53516300ac6300000000", "656a530000", 0, 1609866864, "baf250f3fa4c2871104ca52014a3178a3b88b6469c24e5533c35ce3bf3e93c39"], + ["fe03082301aa4ced049b59283b93df6422e201ad5f6e16b9e4ad3829d53213a82c19033701020000000200ac233604cf02e253d00200000000045253516a3793e6050000000007635365ab53635100000000", "6a53ab006500ab63", 0, 2051985629, "ee88d3b94fdde91acab80b356792e54c4fc359cafe48e42b11816959587ff754"], + ["af08154e0438e96bd856fdf406498bb58f1f5de21aaccffafe033d41bbd00ea0a63608388f000000000152f13e2b6140dff29d808f6e5b61e5c546472089ce77048e89c2451dab8a6a7d22aa64217501000000046a530052c8aeefdb1b41962bde2d01031c6348b8b7d79d5b749931b84072e9175b47022a2390cd760000000002516ae3def005ca167d8c54669851eace89637d00958027973086d6699bbf424e25117cad29280200000009535265636a52acab63a1d4bc4d03d5f12a01000000000552ac53636532ca32030000000005ab5363635112083f01000000000753acacab0052511bfd7049", "656a", 1, 756176218, "c9765b9b16fde530010c8a0df2692803c8b9eab0a16179e8535b67471422a0f6"], + ["036d8ac201d216ba4596166024fbdfd5a24361b0d54ac64d81886e5b9ad1524d2cccbaf97a03000000096552abab6a63510052ffffffff02fbecfb0000000000026565c889780300000000026a5100000000", "6a52006552ac", 0, 1518402014, "fb08426def19493c8da4c4067ce0991bff96af0f03f975cdc30f50e1d370152d"], + ["ee5fcb67028033931a6e11e91b9f4b4a5a508950539e140ee37d8dc77d8731ed027e0f4fea03000000026352ffffffff0d60bced428660cd6ae668c9f32e4d5e4aacc8c2e180f151fefa87ce7b5db2f1030000000753ab6565525352a8ab84c902babc4a04000000000453525152c3d7a400000000000463536a5100000000", "005353acab00526500", 0, -1394714940, "b1c8abbcb97e4be6e33a96f79f27ed5d38063bd68b72f905cd2840c2909b9a6a"], + ["32ce4ea80410fa2ab350ad584a890aa88ecca7baf333276dbc6357f6b0daaf53938d08399600000000046a6a65acffffffffe2b526babe44b853bc77b1c7c9d2b6329b82a5985944084ec74005bc1d53ba9300000000025352ffffffff75c42ac67ef2244d459b21e797e06b2bb9ddefec38966c45284177e20c02ceac030000000047a7b2e671f260190afc94e4706b16019843d5d9cce38210821948de408d5a1d33a46a3700000000036a6a00ffffffff04ad67e804000000000153ba4007050000000004655300abc78bc50300000000016a7c75ed010000000001abbe52a39e", "51ac", 2, 1961803132, "edcf886d5b2458cfea55eef1dace5a4055d6a12affd9f52d06bbdb5106750fd2"], + ["4a087f840228b173e8548a1f0aa8e011d3d3af2fdff8889935b487214342fd55f2b0848456010000000900536a526a655265acefa8ecb6aa679f8a0e91bf267d72a25c289c52aca8277b38e0c77959a7c3a425a6be0dfc0300000008ac6a006aab005200ffffffff01a4851c040000000005abacac5351cec1141f", "ac0065ab", 0, -1644738104, "762a6f4837db2c134eb772b8c4bf2669f6e7ef6f05ef4d9bf7d968e88f4ef1ab"], + ["af74574903e8c6d3dba56232702b5d9797c160128358b2927106a697344c2327676b5cbf1d03000000045300526a8551dac69a0bf5efecae4044b6212f1f2bdd97842faf81f3c1cc2fc1cfd1e6c177e322dd020000000003b2f23c45d234bf1065ec5c72b9e16e074d5c6f82c8d0026ca98a5a928f4d0bf5c730df02000000036a51655480e42e03ce902a0100000000016327843803000000000753ababab6a51009d267f050000000004ab65520073fb890b", "536a6a5253516a53", 2, -1419329296, "44d75df5d21345526ed6a6e520f383ef32febac23a43467d0633b5c941cefce6"], + ["f7810be4039b35c2a5e5b2914470d7ac60330c9a956e42fb45053f721052545d6064da583c010000000865535251acac52acffffffff28f8c4c5a0033ab462ac72aaec30be49406095339166c1364d5f002e92f8f830020000000400006563b177cfa00e3fe7466158e9fd97abbe710d83ad6ea2b6ef1675912213434c1913b0a15032000000000453005265ffffffff0312c044000000000001652887c2020000000005520063ac6a2362a105000000000351005300000000", "00abab63", 1, 1947040372, "acd7a34b9e68bf5cce203f4715b14643adfb1bd32b230ea170253013ba5d9761"], + ["85123f2203d9737e9bbaa0c82bf74423448d581a7f62803cab42fe539d95661d15a39915aa0200000006ab6a656352acffffffff5cc3ee1d708f84d276217de7e89b51149e41fa41404ba1082e243638e332781f010000000253acffffffffdf62384ccbf5bc6dc652922a2ce7480252eb95dfaef943cc62e3069ede2981d90300000002ac52dac46b410162042a000000000007acac52ab65000000000000", "", 1, 1020733685, "2a878c872817d16f422c4fb5a92ade2c3e0642a01e390124d61bd9c8f562e155"], + ["703b78e202e18e060b9b9deae328b32aadfe27f5b2fbf72aa4951cba38b6498d90d4e575c10300000000ffffffffd7646c08f8e07ec291e34da24edd7e46b4eac1e90f5396b725f6c90d8142c2f7010000000253abffffffff01a52f3900000000000000000000", "abacacab6a", 0, 1723666133, "02fb2300545b29c2acb144e88e8fe4a010938e83dfa660ae37cf3e7bd447e99b"], + ["20efcf3503a4370120e618a53c7db8af8a4621a2b2453b1b27357a27999b12361682327bd5020000000953536352ab6a51ab6affffffff38f43e9e317a236e948ebf8ddff6bd7823579d4c4012086810d5a96a200bee64000000000100a26ed6a54bd12e3bec2f1a29f27e70686d01546879e5a931973cfc37aada89ef2ab9b4bf0200000008acac5300ab63ab63ffffffff03c095420300000000056a00006365e50d380300000000046a6353001252930300000000050051ac630000000000", "65ac6a", 1, -580765583, "23ec08111cd92e36503c5e10a38bfe2d95bc9ee0ffce57a2dc969f1b5cbffaef"], + ["9c1c25130277b8669ad27762ca48852bbeb873e7ae0e2a0b2537b0127cf5cc3294846194270000000000ffffffff735d367098f5a59607011d908cf95af2cc179804267b52a6e55088c7d6f735b8030000000800ab006a536a535152e4dac303893b5b0000000000086a53656aab526551f67894050000000002ab52e1f228030000000005ab0000abac7c87deb9", "525251abab6a", 1, 1745196926, "72fc92cb93e2482b206904d6a338c0d55def099296849cf69b3982df323c216b"], + ["a553a4970479037f789762c2c5d0721566d46e5bd11bf92e260edfcfcef32078089564c7830200000006ab53525253aca5982a4886f76ac659957b24002c79122b0dc4ea6b10550167791094c4d804e63ca37f1d0000000005ab53abab65ffffffffecb75886d7b88997baca8a670d3d0ef680f95a05b96b79ad45313a816322d26b01000000026363ffffffffa9f077ca7f80959152477dc00222e550d65ea570542da2897e4ef772cf2ce3450200000006636aabac536337bb9ce301d125160000000000096a6a635351ab65006300000000", "53526a", 0, -455161783, "0336aab78f6fff3506dfb72fb0388a6046a3f1d304d80a94e8a5780682c3da74"], + ["84bcd89d036aa4c730fb811d9a66a23932ffb4cd5bf54ce0cfd37cb32e189a07fd3819b27b020000000036b05d03caed265d48e8b8997d38fa7e875fa2ed2c178d05ad033aada356b17804333d660100000000ffffffff3d289ed9bdf02fe59e43d0fb69356d584df3b4c5027a46916dd4046e15d0f81f0000000003ac63ac22748f40049b984c0200000000060063ac5165650405960200000000090053ab51ac6aab51abf2673404000000000753006aab5153ab8421490300000000055351636500dea647b8", "ab635163", 1, 695688826, "e93fdfae31599a2dc452508daf31b22d65eb5b94da5bba72a9b6754c1f99d6ea"], + ["1003804d0287ce85374cf8fb0db61f5e3417cfc93219d9a7fe09482c905f2a5194c8fbe48d020000000952ac5363510053ac63ffffffff6bdc9a2920222628403f57093b803d58f6f2b639d1765e81d3bf758dd426441e01000000076363525100ab00ea56376203595da10300000000007d5a8c000000000007ac5365005363005b0342010000000009abac516552ac6563ab9f4dde58", "006a65", 0, 1562923717, "fe9dae2d5519db49ddb5cc4048bce934d5c3e1b2ce94faff3efc791d08a40d5e"], + ["2ac3e90001b3fb63cd5b2c2d191661cc874ebfb4295310c6d643a89e9ec0c0afedd9678510020000000653ac65ac5263ffffffff03a4abfb040000000004516aac6a14fa79040000000009515153ac53655365519cbdb00300000000010000000000", "", 0, -1357522189, "f6c82c55826c2d980a2e9237ef0323d93399b46b01f679c31351f5a9ef590b7d"], + ["dec63a2d0161fed55b5977cefafc1522a914641bd4afcaa8f66cee5abe53664d99ade4eec2010000000863536563536500abffffffff0188139403000000000900536a5363636a526a00000000", "ab006a515300ab53", 0, 1191821556, "52ebdfbf55791227669a38a974109a307e96cc36784c6d41dc8d2c473fd7b232"], + ["93614c800165d6d8c3247cac8191914f50e8d99930e7214dbdfe9a274e8c52d896b51e58c302000000055252635353ed13858803ba15d805000000000165555f3e010000000004526551ac09c60b0400000000085351516a5165510000000000", "6552ac51ac630052", 0, -548703935, "f8da1521ffcec6edc24d32865f58374ec6f48951e69a7a19767188d55f843c0b"], + ["7f2fab7d037434f91372dc161d136af1dabff445c02b9112df45fd6054d0194deb798a4fe80300000000bcdabf9dd5025b9584eebaab96bd2f4a941bda28dd415b0f757a53b553cd5456fd8b2bcf0300000008516a6351635200513a6014ed9dbee712df4561021f34ae58e700022e48ea802780d949bdcf42b577ca30478b01000000030000512695394603af7419040000000005516365ac63861b7a010000000007655351ac5100654e851f01000000000953ac5152ac6aab5165d0687cbe", "abacabab005352", 0, 1137989862, "59fcc885f8facc1f5d2a8ceedb3de10ebbebab24a8cfd2d71cd8538f563d7c66"], + ["0c3bc27d04cd54e99a550fc26013242c099ea0ad5aa26ec0aa82d3ba35288658943dced7ea0100000001ab08aeac299b844d40280c5c6ddda582a8c530268aecb51e4b7a78542cc849f4881ea2a36b0200000009ab520065656a6aac51849d6501f44c784588311d7e805d558a980a3eba0bc8e3b9ec9749b64d1d82792f45189b01000000046a636563ffffffff440fd264d7a1247375cf1a410c030aacd2a6b661d1e2657a4367f9e5af662bf30300000000adb68e45011946ae0500000000096553abab6a656365ac00000000", "", 2, -1375386659, "ae77a8dc6899b68d3071ff53f951d36bf0c57ac8b3e6f83f53fc21d2f075a22d"], + ["cac347fd021289ff2ba4147a0ff1acf2e32beef731830dea3eb9cfc34a0cbc63d7f37b38ac010000000852656a655253ab6affffffff9c9a5c34408b91f5a8871f5326434518474dde273ba80c0623c3caa6582ad1ef02000000080053ab5352acab633ad90637032b0a8d050000000007ac536551655100f42dec05000000000563ab0053acf64598050000000003536a5396d7656f", "6351abac", 1, 1949898741, "fc2943860e4693ded1781cbe788c50e8f426ddc6420e820cbedeb8d1befce8c3"], + ["dd37241c041dcc6f7ae5d73a888bf51985529339dd5b5d532844e4f2a85d475640340d5a9f0000000007acab5253656a51ffffffff2c25090a9f51e22222d798a4a3370395b4e1cc7101b4349111d306d8f23526380200000006ac65ac656a5211b734d8e6540c37c88ceaf61fec3d84dd1ac2c2a59b1fe77162f0e27877a71c1eca9d180300000005abab52526affffffff0abd4dea13f387d49cc95cad9f4867a8be539ad2c4ad794fcd35651ef86e3ab5010000000652acac00acacffffffff02af3833010000000008526553636a515100b0ab9602000000000900515263ab63650000e0572142", "53", 3, 496588140, "bf67fb921b9e7ca862a60bf27f21b2b62b74c975847ac40477c1f13ec379a302"], + ["e437e82f04a133bf8308ae822de296828c28d8b7f3a2429410ae637de2f8b45fcc2da1de9f03000000086aab5253ac52ab65998ab461f7cc85e2f16bbf141c1e85937ba0acdd6d39ff0dab1531599e14d9830c87b8960300000000ffffffff200980ef9409636aa1a3b924f671e37ec5e3454497fb8a8b15c06334f19bdca40200000004630065ab97d6ef643d09e59dd1494129bcfea7ec8dfa333eb6c2f43f18d8de1c910dfc849828c3aa03000000026a52ffffffff0417d266030000000002ac63575148020000000006ac00ab52536a34d8960500000000055263655165bc326d030000000002ab6a00000000", "", 1, 1578693994, "cd8de503c095dc07bdb62fb2bd4fdb0616cecfbd845a2adbd7a7c5a01572e9b9"], + ["203485c1014a577c15ec85420b2eac2e95a01099b941a51c547634dca9429ead632afe69c7000000000452526a00ffffffff0261ac4a0300000000066a6a655100630f3dca03000000000600536563005120420098", "ab6363", 0, -354481187, "908d424ee4141a8a31eeed39c25595462842499f88e80f5bbb42238992b9d0a5"], + ["296c754902cfe6cc615a4a62a443bc459fd5c3b89251ef97aace27d8fba1fb777bdfa905f2000000000552ac6a52acffffffffde8dee72776ac328ae43596e2f1a459553e442f475f14afedea2ae578ff8f2dd020000000663526a656aab1a6b3f67017d381b040000000009ac5251535251ac6a65c6c1f408", "ac5200acab5363", 1, 283942622, "c324be5a8bad826c5cdc44d088f284133d6905f677489275eacc0b161454ce82"], + ["8e2a6f45040be0d6e55193144a779986fc620af58393268394a9e6bf009b6860e1df5a8e4602000000086a6a630065005151ffffffffbf834c4aee66e77485c75f3e18db5b51e6f2005a7405d3cc7bd4417fceee861e0000000009ac5165635252000053c4aeff9a7600ab18bb7483cac4fed1a2079e03d1e5f000c9d1016b3817e469fa0d70232e0000000004525353acffffffff960fdf97a590edca5954e3a6a8655ca93c232d76782df91090c1cb5e3664ee130000000001530002744b0240849c0300000000036aac51d2b2680000000000096a51515265acab51ac00000000", "65ac516a63", 1, -303020850, "8ace6223cfcf7eb46a8ba8a5352597501acc172b786385a4b69301d309f9343a"], + ["dff2240c0426a3c8f7050f3642212f6c9848352e414132e4b6640f35e5110f3910e4b4c3610100000007635153006a53acffffffff3ec0c6bba785e57ac3b7c2f55ebf87bac33ec6fc810b485cdf3796e7df5e0e18000000000951006a5251ac6a6aace9d195e284d6ef591f0f2b11aca5bee26614799835daf423ad850303eec906cd613a8bf0030000000252ab386a345018b42e6e754abb0635f0f45d19ff3ea3c1e15be8a1f66ffa9b153cd40a6fd4460300000004656565abffffffff044d645a040000000006ac536aac5251e224900000000000076a515165635252864c260500000000096552636aab6352636547cc19010000000007516a6aab51ac00a8c1363d", "ac5252", 0, -828272701, "5a81cf560f778fe49917e41526cf4c79b983c98ed48ccb374f24b29cd8fa12fd"], + ["008297b702696db564afc65e5aaed1ffbb9aa96541dce28c1c8a64fd80502b743657bbc5500000000000ffffffff9a4dd4d3f3a447781c4ff1c79035be467d14ca13ba11f16159af09f9b3cd2624010000000453ac6352ffffffff042cf2a60000000000085152acab655100638645e202000000000953635251ac6a52ab6349d9070200000000015346b7c50000000000076aac536a656aaba874e2ab", "65655152535163", 1, -1009703850, "17742ad759a7371807e3788cd4867054fcf12a39beadb59c50189392624ef370"], + ["1616fc7302b4be48c6f378aabee6929ce0a39572c4eeec99ae97420f700ca73e46c60695bf0300000000ffffffff9689768bec9fdc3482efbda9dda5cd4c60a36e13f843edbbd6e364a136eaa71d02000000040065acab7a906e7604f75435040000000007ab635165536365b55b320400000000010002abdc0000000000046a5263538b8381040000000009ab515153006aab635100000000", "00656a0063655353", 0, -1062029060, "f3380efc58b817c02996f282f00babea3a6b2159399912630954d7c1c18cd0b6"], + ["fd9dd724021c26477d7d27661b7bc08a0c4438695558b589167f854c277ab9e84233f5dc1d0300000008525200abab655253ffffffffc2df54747242ac7414150b4e43e3ce1b79abf1a1cb5151a5b97f7d665713816e030000000700006a6a6a53acffffffff0202fb04000000000007525352ab006a6a950dc90300000000045165005300000000", "", 1, -2054636061, "c23ddd5a9f9ecca858ebdc9afd3388727ab5b07b9437494a59c9f449a46d3a0e"], + ["2333402901a66a9d538032460d96f64e498d8e26b9f56d49e41742c239ee972e87bda818f00200000000ffffffff0247d9e30100000000009430a400000000000553ab6a6aac00000000", "00656a53ab", 0, 466640381, "0cdb160f0ccfa002426cfaff0eaf0a21857105e2f021713b147ef9dfa2c24295"], + ["191879d3048855fe182872ba3ff79a5965e72441a13dd48697ff3cbd61c49ce1185e5083bb00000000075200ac6351ab516d6f690b8e9e77254e5406a663ab02f0a643714d5ca4de01c60bd480016ccd42299ce4f70300000008536a535153536363ffffffff8623e705585253c87c5333bc0aec35a64863ed849b1d84ef7fc205173d21bed40100000004ac515153ffffffff8ccb9aa3d489adb234ca0249f072baaafb47ca0d7218ff9c0a86f164aa0c9dde0200000009ac516a52ab516aab632de6d66a013d8277030000000000a382c89e", "00", 3, 1086809451, "2d837372037960615e0c7061d6ae9f5e529245c912e7dc981246a8e9f4d2f5a6"], + ["282927e104e9201a65ad1c07bd03d4116533ba0ba5cdab109dbaa10d5cd9c9773c75bcff09000000000800ab005252516a65ffffffffce0c035495fee8abcc9d181a8ac0a0652c68a613caab1b58bd67e191997d052502000000090053656aac6300006affffffff4f323a17d603cb4496709149762fbd90855037fc30cb61403c0088df3a271e35000000000253652b1481df9c90d5188d4a6df25dc403669241a045b2f3d45e88b3b1eb3c4a4554d0f6bbe60200000004ac006aac4bd1225204b626ff000000000004656a6565a26a03000000000003656a65d737ae03000000000952abac516a5252636374891d03000000000451ac6aab2a0b476c", "53535253", 3, -1942303001, "17b75bee3f46abaec12b9605fa3db813b7469b97cc7f193d267bff47d0424531"], + ["330fd883041fc4d838a220843cb0b9fd8b789f993684711159073a015141393c4f14a801a5020000000151fffffffff1fc24d2ac2aa576289fe2e58239e5594234c806405d70a308d95ebc381ddefc01000000066552ac525152ffffffff4ad63770328c83681bc3acbe5cc9372518fefc25e57be7742f9c14d3489de82c0200000006536a52516353dc995f53c4601b679e3033c146bd07c930c974c4843c7ba4d24083d3fa5c21703ab6d49b0100000009535265636a5200ab52ffffffff0283c40b0300000000086352656300526553fe4ae002000000000353636a00000000", "5253ab00ab", 3, 1804157812, "e5dd1c349bc2131393be98b58677d3a95c19f60cfd615aa46cc90627199532cd"], + ["4c06ef2002200e6ff17bf1e5d6287d43455b5f02572eae36e9afd5ea4c26d24c19545293fe01000000000df61371d32aaf1dcfb74097ce74e9213505d4d70918354e45c0745821c1cb8707fc7c560300000009ac630000636aab006569d6d3e70273a3500100000000046aabac63d36cd0030000000006acac00006a6a00000000", "53", 0, 398769497, "de9d8f2bd03ecf8235eb61d948c54355aee801126300b9bf30e8c5724d806334"], + ["ca03c111045a6d54cc95e2a7937f0246d3b18ad653d90129ccebed8cc3a83664ff22a0dcbf0100000008656a516a5165006a476ce7dca10bfe333d317f61bd0de45b6cc70fd4826dd8af0014653f5df223062339a9ab01000000016affffffffedc657d883e9aaf9ca716996ed3ca9a8c7d65de5d2f311a310df0bf0f7eaa8ae03000000085263ab63516a51abffffffff1d7a98d0cb2ed29594d827c7681d69219e8cc2e43013dc8d724345296fe383ad01000000096aac6365abab535251ffffffff04311a87040000000000f16338000000000000b523c3020000000003ab0065e9530a020000000005636353ab5200000000", "", 1, -261976591, "47b8e837e1ad63830c437c3e4e6fa3410189910826c99db9464cdeea6bd40f50"], + ["437f8f7e0344f9be49dd1db70310de4badefdc728440ffc54fc8f56244a28b35d564f9efa00300000009ac51006a63abab006aa131e799c3cefd30c75d907b1dee518578915560e430859bb0e8096a482ab6eb2dab8b5c0300000000b30c867e9821a2ae492daabb958d0ad92e291d071beff05467670482b2fef1d0ad68fd29010000000763536a53525251ffffffff04a55a1c040000000003526a5140a7450100000000001f75770000000000066352acacac6ada8c710300000000036551ac00000000", "536a5363ab00", 0, 1189054318, "eee78c773bff97815e501e530c92624159c9f08b72bf9240cfa2f3968f7f23fe"], + ["db73f2ea018cbd2d3387a11dd1dec983ee22f121513afcb65040ff1a3a6a7336c9657a687d0300000000ffffffff013d69d603000000000600ac65ab636a0d777605", "6a53", 0, -1669713026, "8d02be82fb6fcfa6a173c9291b05cf5cb3abcc412820adf543a0002cc8b931ad"], + ["4c99f09e01cbcfd74cd3603855ea0ac5bcede247b86c9f7fb8e2b680bcdc12ad613c846de5000000000465510051ffffffff019cfe4a02000000000800abac516a525365b8e2a663", "0063", 0, -966786059, "39b00f8b41466479d509ee42f167b86e5c84ea8d7f3325eefe78c5a474fd0ef4"], + ["33f5072802516325104f665e1ff9763288dcf637f4c3d28927085d664fe2d2784f5c646b4f0300000000eb8da8fe457974153a0c5da13be0420c550370552f2c5a923ff6bf2fe43590ce2cebc562020000000251abffffffff03633ae3040000000005ac6553636a8b3e560400000000016a3eb46e050000000007abab00656a530000000000", "ac6a00", 0, -1028263044, "8880e3fd1abc0accdfae4e3287f9ee325de0ba2563ec3b84559c81bb718da59f"], + ["ee468cd601141cea4f0ba345080766206d750721a826f1bc2ca59ec8a122d281e0e575803f03000000016a42b07d8f024b65b5010000000004656aac6a5c5a3e04000000000000000000", "5265ac51", 0, -1618410541, "cf2be69def5e465ada46c13698787c6551e140d9693878a733195160ac073586"], + ["e134fbd701dfc518c92cba484a85e24e199fbe5e50588e7246bd6888d1237205050494362e020000000152ffffffff03e2a0140100000000030051524a1fc705000000000152a5f2e201000000000000000000", "51525353", 0, -824539953, "6155d2c976c17cb2b6acc7c375b1b86720bf48e3443a8494cc64f1d782704bbd"], + ["662afbbe017832658fc2245125c8ed48618c8e54d9f13a1c7654d2b3a50ebbbd98aeec29e900000000085363ab65ac6aac6affffffff023aca640100000000076565ac6a0065652c5821020000000006535165abac631e7f6b8b", "", 0, 1833232621, "867249c6b5d64b78357e5adfa9c72abba49e5b05ce182da26262d12ef8d850d7"], + ["f2006c92016f81342a63e166ca1810d713b8ce8c660f4e7c78927b8be4ce836550f8f4652900000000086a63ac006a525251ffffffff0116287405000000000553ac00655200000000", "53526353635200ac", 0, 1392208218, "37ccf5362dbf51c2e81a55633c545f0c49fd9b7a3f47ba54ed064e1b4a29943a"], + ["6cdc86020278df051ea9992c9f383cf0048c060fc3c751429f2def808a520c5728b771e53802000000066a516a006a635be941d48406c7a7ed795b43edae8dcb36ff027777c9eb8c4b82f4b172a4e6fbbf5c80a101000000025251a5e3505a03b16035050000000003ab536acad11c03000000000563656365636322680100000000015100000000", "63ac", 0, 746012736, "952e9956e197aee8e52f415eca92c2be0e7d50a293abd649494ccb9fe519f0bf"], + ["7658c10b04f60db6f0bc2b89b2943997b3c7f60150df01517ac9440e4510bec20cfbd530340300000004ac635363ffffffff32515d563254d3ac95960de19881f32aef4f69d3d8d256e8e9a74de36fc2bfff0300000001ac5efcb354ffe040d94c3980357ec7f4e9c12f031f5ebc339e3523b1ad27de57ad5463598b0300000005ab63005151764ec602aa8cc85159d24d7e600f1fd89cab4b822aff1ee681d13faa0ac89ddf0f9659800300000007acac51ab525100a388019202df567d02000000000865acab516500ab6a5c03f601000000000952515265abac0065ac00000000", "6300", 3, 1835579858, "0ccf891c0ca29d578cbbb65711d7aa7c0a7b7109138e670a4c89ca461bd9b2e4"], + ["3a90b6c60377181a3157a5c3235d9367083ffba7c978a76b617c57c7a75d28bfce8766c92900000000035200ab8bdb10b9c9fc48e9f100c18ae84d455bcc1a35380d68eeb623b55d3e4019197342c33fbc02000000001f826adf006569d0f2b72dc390b751d0b3fb0a36c0d514b50d2dda84f0f04abc7ec146f60300000000dacc3c49039a531e020000000002ab51a730350000000000026552f7e30701000000000551ac63515300000000", "6363ac6a53ab5153", 0, 637849705, "d82cbf23a496d9c7ab92f890ca3ce64ccaf52e9485d5940e31a780f452101208"], + ["09727df204963addfd3e40dd6aa20fc556521dfabccd19f0505770a3c402d83da875ec7d18010000000863acac6a655363ab584e4ffa09c96d372810b35bb6df7b7f884eaa8979c7e14dcd83f38702741c0d50c8033e0100000008acab535351ab65abffffffff353380e574aa17d41e67b1ab39f3612109c7c44be1d7925263e55db75a0cf8ab0100000006ac525252526a40faacf5b0f29503a821326b4859d4871e8057b24a2cd7e1fe894bba10bc20edec842e23000000000751516aabab51ac04e256c401c43563010000000009526a6aac6a5265530071f77cfa", "ab6a", 2, 1302297184, "af7b5d4bdd063a73045a52e784727d86f3d8710563ab0904403309265c6ede90"], + ["6e4bfb5a041c4090f09aa618cf0d554c3efc49e67375fcce56b880ab51fd58ba0d1721065f03000000076a6352636365634e6f20b7ee5df6778b08bce76ff7bff76de31ee2bd28312f54eeded5cab9ccb35c99f0d50000000005ac655163516b080adacdb57fdfd387a84354e1b1e3fa715ec6814768f2b12da41adbe5becd0cd187fc0100000000ffffffff32d0ffbd0b8e7246e32cba7a0fc05693647bf48735f5c346a4898d2ca1c022790000000001538a3895000469660f020000000001ab167f13000000000003acab521bdc45040000000005ab52ac006a72ea6f020000000001ab00000000", "", 2, 1511369816, "5db3098a266da1ff3500f71ae0618fccee1ee17d63e49b7160df06db1d9b71bf"], + ["11694e110457425d794f39b997c02eb69ae3b59d4e044decf3c164bbafee947024feb73e39000000000751ac51520052acffffffffe2a2f91eba0c9629960b240072b0c4568a1ae67de61c009b05c1113bdb26f59902000000026551fffffffff2389e457d2f7314de5c47957806f0ace2ce7cccafba4d5aaf221a8b9803b9040200000006ac655352656affffffff028c68f084cc35906a912da135e8f870fef629c785476c1a4daae990cdd3b4d102000000000af4f7e501a55b18040000000008636a6551535363ac250152db", "6a5251", 0, 392976888, "a943c1704e39effec5e7191ef9f40bd7850f3b51a9bbe4ff99908869b225703f"], + ["dd5f928202f750863dcb711a8a6cd8b733d6830ef454bb960b8a7302d083156676690737120100000005acacac52ab28d2f50ea26ca7cbc2efc3fe34c42e67b2b43656ae9d124e499d879e79c78339a81983e9030000000863ac6a52abacab530bfaadbf048c693d04000000000551ab51ab51287361040000000009acab526565ab530065a0c4990300000000076a6a52656aab53f317f00200000000095252ab6aab63ac63638829602e", "65ababab", 1, -1198424370, "21c21bd741ec94be9279f0a22ba45d9c7fc0d859debe6fbd0db93e5ea5c02ba1"], + ["feff23400390e799aa93f64dd0b4512235d8580150a753568608869ffe694832d3d46cfb270000000005ab536aac522314fba594fe54a5bdf1aae6f16ea2d7386619587895cd95631300e53bab463a20995d0e03000000035163acdc0bd71c5dc75b4d138d5740670eaae244475aa95448891306302b6b65d5d3b3eb8ebab700000000006332ff0b03aad7a50100000000086a65650051ab516a30709402000000000100dee7cc030000000006526500656aab00000000", "00ab655200acab", 0, 1930467949, "0ea3b96fd77ff39012686acdc7f57758c0886df833051a2b159a9b24161da5f1"], + ["9d44cfb001972d5ef29bce9dbe1808281d56ef079d852d24743d3871711aeb30fa03f0e3900200000000ffffffff012a8da40300000000095163516363ab00526500000000", "", 0, 1541309285, "13571dccc7929a516b5939090a9958fea36d93543936ca2503b409fb927a4520"], + ["672f09f803af19308ae16c5a29850fc60ecb2634124aaee4e308b6715c57d6c4b1691bf91e0300000008536aac525200acabec78dd4f864ebdf58649a45c993121581f4f42336679498770a52c81c0ad3d3befae3c190200000008005263006a6a53524133f51d63ff55f63b8e3ffb0d3e901856b1c0860370fa35befa47d968fc7045c49b754101000000040065006ac4d77f7004ceb5ac0200000000086a650052ab6aac6a199f04020000000000c1d2c804000000000863535351636aac006a036a050000000008510051ab005200ac6416b908", "", 1, 203456625, "610d291d4d15b0a61e2dc126a1c40686551998bad66695940df0548dc80c97be"], + ["a4125b8b03f55cdc61a17f019434fb4f2785962caf1b615794f726d02e8a5f8154bf5fbdf802000000096aac6a535163636300ffffffffd0436069c269f98a6ed047801f22804cc3484fefff0b406e8c4582978ff7ba92020000000453650051ffffffffca482ad8b8857abc872b1d7ce03b036deddb802bd8777ed2afd01d482a3f12530300000003acac518f23917b032c5c22050000000005006a516552ee1bd70200000000005fa3e80100000000036553ab00000000", "ab52ab53515353", 0, -1848863012, "1573616119cc8290af7779979c732f8cef90c83857ba13739dcf7430e3791dc5"], + ["58640d41027892d5a2d2aee44ea31b72406fdcf102a0466d4389ef0c45acd2121995d8baaa020000000863ac6363ab635265ef3a4058042455df67a5994129b11eb832346cad6857f1c8300e178a0e840a998605099901000000036352acffffffff04a55ca10200000000086a5152635153abab877096010000000009ab52635300ab51ac6a7a777e01000000000251651661f5030000000002636500000000", "635265ab", 1, 1382401247, "fdb7fbe7c09cdbade6f65471f98c2eb5ab0ebbebc953dc4d55fd8567b7f40a9d"], + ["9ea85a25032d1172afdd7bb7e356d0db21fd948e3197b6830f0f8ff17cfe683a2d6b21f5850100000000ffffffffe9da22a144ad08e86f8e28840b96a14f7fba45b165d83782d6b81e6704540fe2020000000165ffffffff26baef73d3fc8d04686fce436da2727455ac14c89ec8adb8e70b96f5b6470bfc0100000008516a51ab51525152ffffffff016588ba05000000000352655100000000", "51", 1, 1437165164, "c398d55fb75040131ef833b405b3d05a727df651a6985336716ae32289fec061"], + ["66ed3265043275d0323aeb5871bc0b5b57dc76ce7380363a310329164bbe8d9bd5173943ca03000000055252516565fffffffff4fdc1a35647dea442db448a56f4caff8586a29ccdd3bfed802ef2ddf3c4dd8e020000000251008b878468cd77681f2ec6278848f21e70c68285f3e1a773771c2ba7b68a6044499a3cf92a000000000152ffffffffc60a5d5e35b057c860f76635ef3e5203957e71862991c0f8d8d061a128161d1c03000000095352ac516552ac5200ffffffff03779d0a040000000006516a63ab6a00f51712000000000005630000516a3467ee030000000002ab6a00000000", "52", 3, -552425221, "3105d806c74005def990501815fe9d2988f940cbc20877ea6750ac2036146fb5"], + ["4c98bf5604cfd794eb23faf3b8a27865e93bb65eb983b0bd688bee47e921eca646d48559c70100000007ab51ab6a515100ffffffffcf815101ff838a1c6fc53943230b2d28f45b28ceed111c70fc2410b88823a464020000000765636a00ac52ac056a0af772b14b7ab9ed5dd545d181f08bb1ca67c65f9de1779e37f984444c4ff8f7e88400000000000186830fb42a9f453167b906367cca210676524b443d24c591c098ee9ba756ea82eedf650000000005516351ababffffffff044ad078050000000004536a526a7f36440100000000085351005265ac63009f23530300000000086563ab63520065acafeba60200000000026aab00000000", "51", 1, -205319483, "96b06aab614c8a2c702afb88a5264ee0b7ad2f70ad5ba39078721412022b45e6"], + ["482e6b1e01c87a9710900fa50c5a373afdf085cecbfb664ac12c9353eecf03a14f5fefc0b80000000009535300630052530000ffffffff03649d6e0300000000002fcbd9020000000007ac6551655353527de91e05000000000453516551faff008f", "656a6a530052", 0, 1620632132, "0da1addab6f44eddb3aee13a456118c1ba5801f218a64090a849400b367f23a4"], + ["57c49c50022a355a27cabd9e34eb5ef56f6eef69cd0aba0743dec3815e0e0d44a28dead3c2000000000651acab5253ab50adb02df5020f00bc538a811f6095749f727aff77702e9809b78985c1a57f299273715401000000076aac0052ab6a6adc3e81d803e8dc4703000000000965acac52526aac65526fcc87050000000001520acfd80200000000026a6500000000", "ac52ab52abac656a", 1, -163100218, "f8b372a43a9cd19a25dc61a7fcd17444505875c21c337dba956e6a04b21bab10"], + ["a554ff2104617a8a0a26cdacdba7c2d60bbd4ae069e234fc3a4b117a12313024f441872c8d010000000600ab53630063ffffffffab7241cfd5005bb28a63ca1a5082090bb35728eca3c0439d41b72f1065682c60020000000151c6f927487c4ad26c78dba7cddc820c65ed075786ab0cfede1ffbf8a40c8cc4e557338132010000000752ac005151536a84bccc87eb7f5ee1642972eeae9c0f333b0b9359d34426e4c5f4f93ba02f2225e493309c0200000003635265ffffffff02e70494000000000004ac00526a2590a404000000000951ab535352ab526a5300000000", "5365", 2, 66744173, "f9548a73b4bb103e1352d2406531a0b7b1bffb665789f588b8e3387d4ccccfd7"], + ["19a642bd0249fa35a7f2bf2df9a9d055ad1317449ee0574fefc7a8b15e557bedad7adf70f80100000002536a243af1b1e48fe79d07e41220ad6142999b394900c6404460797c3ac6d8d322d9c1addeba0300000005526a52ab52ffffffff024ea4570300000000026351b5896a010000000002516a8d3137b1", "635363abab00", 0, -673319988, "73767fc010ed110baf73e951c1eb32b437a3cd4d9325dd435ac4ede97f764d21"], + ["0dae047604b9cda1c69c3fa37a4efc07fc095d5a52f463b565993be01aa84fc8b8da40c400020000000400ac526affffffff0e1bdc13470ff4194ed7d96e186f1ae4e64798994e66ecc636a6589910e51f6a00000000035353acffffffffbf365a9e9539fc146f4f9467e98b60fbf1092fa80a46153b7648d786e7ca37b802000000076500ab51abab52ffffffff6fa605f94fbd55e50085c57ad2a64803afe311a964ed09f7f5568508c923aed30200000008516aac0052006563ffffffff03d22b7d000000000008ac00ac6aacacab516a44cc000000000000dd7ba9020000000003ac6a00cf1a3ad0", "5152656563", 2, 42290753, "5160e17c7a90095123dd00daf226487ecbc9d577fbc4b0370d031db521da84af"], + ["c4f0d66f0203f96f0dd2e4b70b390ca298bc964892ce7a0a080205fc5680f64db62f76e2e7000000000952636551005251006aaa124d0c28884503299010ff74911cf7edc60a11cc30054451e1498bfc260561fb1831fa0000000005656a5165acef0ea91103ae5f02030000000006525165abac63d447c305000000000452515165c982f60300000000016300000000", "", 1, 810173519, "0435fc23cbcb578b1bd5106f86c5e0a1dae97a3119c8c536331667500293ff46"], + ["eb779ca80280eb490c9e545fde1619b42fc23dc605e677c22fef34ceecd0d6cda33879dcdc02000000056a52526351f9b99dc66aaf9ee68f9b51640e581991aa3ec87aa8e777721a4b800bacf2d15977436f31030000000551005163510015fec402551b8105000000000451526aacbcd285010000000006536353510051f2448c7d", "ac6a636353acab63", 0, -657800501, "e1a4e1ed0ce064ad9587e928b7b93d5d30c62697a6f6bd130402650ce857f11f"], + ["f20f5d4a02696bfbb830258af7f15f24e41bb784de852337f31a861e19dd03f55f005cf6ba0000000005656552ab51ffffffffa5ee7929fd229f2e805fed5682dd5c6012ada3693b79e7ba6558f5795f4b2040010000000151ffffffff0463b373050000000005515163526adb15fe03000000000852510065636a636a14a47f0200000000076551ab51ab5353e4eda403000000000953006a516aabab006300000000", "52655351ac52", 0, 1418848839, "d8d50e1259d5d62d9df644d677be773dedd0a1175076dab939aa97f789df675e"], + ["ee26e9c6017a9c9fcc6d1e03da41c25c01ec6777a8837a26a8b5bc050fc7b2ced1f76832d503000000095251636a00516552acffffffff03e1a896050000000005ac636a65ab068462010000000009510063ac51526a5151df2ad3010000000007ab5365636a515100000000", "ab6a63ab6aab6a", 0, 1092996550, "7d3231bec35b86e761c78adfb9f078967271bbee4b232cce22d940e06a6520d8"], + ["dd1ad58a022efdab11378648255678b44eac2765c430bbdaec9ea9b9b1841f9c7b24d168a80000000006ab00ab006552ffffffff34be07dd2d2e2bff66768e76bbe7218fb129ea83905e6763033aac1851f1d9910100000004ab516aabffffffff04c91a8a040000000002006a69a939010000000009536500656352ac516a94cfb50300000000086a636563ab00655294097b000000000005006a52525264a0815c", "516a63", 0, 230618821, "34f873e9d6b2b27dbf26bf6cf282a6588137c50ab61a423c5f8c1f5038455544"], + ["39239ea30316157e8bad50385b1ba3079343d45d6ec0417f9bb71f0ad28ba55052fc009244020000000853536a6351656551d665a342ef0ddda30807fe52f9bd3a85fc382fb9292443aa5eed50060c07ab3d05beb1630200000004530053004f2735bfc59c52cb8c2e5a22be0337cbeca97630b0b51879a97948852682805111b3e5d602000000050053ac5200ffffffff0156936e010000000008ac655365abab526300000000", "ab51ab51515265", 1, 71307513, "46c31fb389bbc08beccb02aa988948ecba31a56dcfdeea9b2442ac8da42fbfa7"], + ["6e97ecdc019e4076ca6761b844cdb7d12ce1c6e90c09023719ad1a958210314f22e6de3fde0000000000ffffffff030dfe690200000000046a0063ac48f8290500000000066a6a636a52ab3bb4aa0000000000095100acab51ac65ac6a51597f99", "", 0, -1304903821, "3b6516d442d0855e1a4b8cb71a10b9b9ed3f04087c9cae52ce3d5c0c3a16399c"], + ["e421755f04a2fd0bde9106df237d8197c7368e24f02e86a2c97356c64de0c5ff4b80c4db1b02000000095351ac655351005151e1de8146f0e085d440e7853da683c559b93c1a2f02b4f72d83ae847292dff2e55908e3f2010000000153aa9f2d98b4d38ae1237f5e04ccc06b1b43a035821b41a484400f41092ae5c497035ec0f40100000008635152abac535365ffffffffd3ac3c0d571b1cf75470ef3c1a4696e1aa423251a2056ae2c5c651309aa0d8550000000000ffffffff01ca4e0c02000000000963abab656a5163ac65a787c11f", "00ab52515300abab00", 0, -110875678, "88f54c4dedd5d6bc39f88ee8c14b58ed309b94d34f2dbcb5249787a6fb938e32"], + ["75eda60502232e1a4703625fae901bc53af7a7b26717547d351a24e0bdf801c45413cef2cf000000000151ffffffffd2ed3999d2e43fbff29ca9fd6e77d70cfbd473688ac4bf93fa178879e9b4316900000000016af10dda9e040dfe3a050000000006525253ab6aac2a642804000000000963ab006552536a6365ed47a100000000000165d1f5650200000000086a00630063536a5300000000", "63636a655300ab6a6a", 1, -1457903252, "1afe9febded5d4097c47c8fae969700dcc50b824643efec71879173530d717c2"], + ["9670f43c0172cfb8d78314c45de4006320ecf2f88f6836956b5348e89f09affde6023575230100000002ab512a0edf720290455b03000000000951ac53ab65acac6565e265720300000000080065535252ab6a5200000000", "526a526a5352", 0, 556931062, "dea384cddb8f87d0cc40993e10b905ba5492077a7d2d30c9e14dc183f2df906e"], + ["e3f2a72f026b3b5fedaf41dbfc4060a7c48e454367bf89c6c1384b175958df55e7696a9ecc020000000651ac515153531fff244f3a39ebe46ec7521aa8516c0bbafb27fb4368fe50f41b23c9e3f963ebccb81cd90200000000ffffffff040a058f000000000003526353bf2f7e01000000000852516351ac515353c28819020000000003536aab9f9df70300000000030063ac00000000", "0063ac655153525252", 0, 1462989399, "39bd5d15290981c7c7a5fa45a6ae0eb71965a8b812db91be1aef3b1dfb477af8"], + ["141637da017e171e1e662c364fe88d6098fd4e7d40fdbb5ec751e8d1b259a6b235d78d20ad03000000026a6affffffff04c0635503000000000047f450000000000006526aacab53008d42c5020000000005ababac6351793eb30300000000015300000000", "51", 0, 452342349, "7a5449187c8928aec43981070fca0e130540464fe5d9902adee000d8406772d8"], + ["8e18ca740287ac1dbd3fc4fe28df0e01801a94d130a8f8ae403c7266c589dec9148938008c0300000007ab51635100ab51210bce2558fb27eda9a427bb94c7848ccf20ac8421a0b7931c0718b16149785f274044990200000001656b32a7c40359f054040000000006ac63ab5365ac1687000500000000015150980c0200000000009582cd64", "0053ab6353ab", 0, 1213364939, "e93c00381a2f1a20b2f3c84fe731542317b7b5487033454b61ee9d6e010b7b08"], + ["f49f0a5c049ba8aa7ee4242ad3b5309af98287b87da781b9187fbc366b5482863c2e80e04c0000000009515151ab525153ab51ffffffff5dccac0bf60bd082457dd5ccf7eb074fac440a695bfbaa2d7ece4d931c9d8d81000000000653516a5265acffffffff5eb41ce50d8669caee9601f2c5b4738508ca2c4675dd8da3a393f0654f4e5e400300000000ffffffff1e4554991df8e78dd16fe63d06f9cda10ecad607588ee6988158e3f696654ee0010000000163ffffffff03344b8c00000000000900ab6aab6a52536553b05edb03000000000074e576020000000005ac0052536adb60d18c", "63", 0, 1249393913, "32d55b199433fa339038a68b94d33f59e4a3e85784613ad648d378f059f97587"], + ["c59489be03046131e0d5a364ae4e8b07a240923930f76a053cdc8477576473c9c792be3ba60000000008516a51005351ac539d561498a168beef313efac17885a48d51fdb186a4f81b6589d097b1ab45c6c761655aff0000000004ab6a656a14b4854d3b0feec8e039115afc536ec07b5f58311ebdce21113a991fac048285d5762f5b020000000352ac513fdeb0e404bbace10400000000076a6a516553acab2862cf030000000001658fc443010000000005acacac6a6391d3bc020000000000af237044", "53526a6a6563ac52ac", 1, 1240918752, "0eb1e03b89f0b3605409362e3acbcb31faa263cfeaa7875665300f832d925866"], + ["9a969cab013dd912bb4db7a1de6364eb2bd888dd675a0b0ca4ab6150234112e4c1aa0900e601000000085365ac6300656a634c63149801eb7d940200000000065152acac53ac00000000", "6a6a526a", 0, 1374262005, "521d2292b5e5d0640db82ee02f390b49a100b4ecb8981e9494b0f55e357f8f9e"], + ["16486b8f04a499b98f0a3ff58ecc1271f330642d0878deb457456afa4e82a78de51ce98ef902000000076352ab63ac5200ffffffff03d41c0a1690612a5d37cb07e14eb5b226fee65794b602d9ecf891c6d2674b3c0100000005636353ac51690bcd935a766aaceda24b4f684ad3f103e119e5c7e57c778d2a1af879893b7a0a2a98450000000006526563ac0063df1feab6fd7f710b855a3690123a97a6e8b56f3f216bbfb4d4446cea2e3da1ab0e2db36303000000036a0051ffffffff0477cabf040000000001ab7c03cf020000000009516353ac6563530063a26892000000000005ab52650051fe43af03000000000351ac51474f6b2e", "0065", 1, -1641197600, "52e2c0bdab251d655e2cee5fec8a4615b7429793bc111ee46d6fe4c266b22109"], + ["d7ec8c26026c84d86bea63e746367faafe3ab1e921c37e7040c4c1479310ff930faf76a0650200000009655352515151ab51abbbe290e594018910655db3b3864be92627da6f3aded1e783976ed740e8e6c3b323339127010000000951ab63535352635251f579a228030132270400000000007cc5d70300000000035353532e148a0300000000056a52ab51ac67b77ef4", "ab5251", 0, -1172531206, "d4c61d6293bdb5bd8b1886505e36928c8d99a6bc43cfd0a762d5dfea57ae3bd4"], + ["17b6ae790249734ad073cd17badaa8f70b3a24b4e4e6cb21c172527e6a0e004cff30ef6fc8020000000665526a52536a8c185ffc3f516a475563584a811d1df1541791355cc792baefbe6d7ba3ed2ca4ab78eed90100000001acffffffff018f283202000000000663636553ac6a00000000", "", 1, 567764476, "6439f1f65214018c3d3b2657f7e7fdffe5d54b6d56778624533bd1c125ed3c86"], + ["c7a640a601754c2c36db1c2c5f83fc6755ba721530fdb5e99911837d1d12660467baa8eea901000000056351ab6563c6486a1c04ac7c770000000000030063527201c1040000000009ac51510052516551008c7d970300000000036a5365667b91020000000009ab6a00ac63ab6363ac00000000", "51ac00655365", 0, -1030243356, "d0b5fc6917bcdbd60643fd4380375a9331a8bd17ab9805b57fa30f20b9f6ef90"], + ["82eed282034fc8a62ebfb9a8b905e3979b787850f445ff158d236ff7909d537bf9e27eea800100000001abffffffff5d328272b837284bd34387ddd9c207d3d308a083402a7424d3abd50bab648c2b02000000096353ab6563516365ac85d03fecf945212f8b4ae740e3d716a8d654f068bbbab021a8ddaef9dcc2769dc739522e00000000025252d11707f2019b8b5b0100000000066a006352536a53d53d16", "ab52", 0, -1575742110, "74aca7d600d477748bcaddc8b41aaf3bb386d910af0f57d976d76ffaca50fe00"], + ["eb32010702b40292e9e1d30c84368fa3caf65be6593d19aa0bdb7fbbf816dc6ab9033db14a0000000007ab5353ab006aabf0e5ab78047821fa53b194a80b36bfa39e7cfc9fab50eab6c76a229e21a56cf11d04cc5802000000076aab5252636352ffffffff0327be910100000000026aac7dc615010000000003ab00006480b103000000000651516a516a659a06748d", "ab656a52ab655253", 0, 943097683, "b318e990481b5dfbd6018272a5b0759c18eeaaef328e70b2b1bdb343b04c8bd5"], + ["3f65190a012a84a3d8fe19080d05d3dad001759e5607c4764eee6849573873d00d552eb4800000000009ab51006a53abac0052ed91b8ba02169baf050000000007ab00ab636a6a52af6aa501000000000853ac51515253ac525ad4c8ce", "00ac6a63ab51ab", 0, 2007740228, "eee427293dbb867c95e8b90aee12cec14c4b987cd88db416a68f63d2c2998db1"], + ["e4aea1e1030a6555076d58b29342f247d6a8871717d1b32653f2d8a509fed514233d43c8240000000001ab1990a2ada8ed5734d65b8243fd3e9a1980f33e59467fd9905e0cd30fcbbc93047ad2f5fd010000000400ac5363deecceb1ed2927bfb8a45b9ea45062dc2e0e2c4aebfc10055c774c5293595023674686a80100000005ab65536551ffffffff01e24b820300000000015100000000", "5363abab63656353", 1, 720282091, "539f72032f85686d0f368867c89485796059d0f294762d9be36cc789a4e7af23"], + ["6d921c740439f5c9bda4d955fcf9d50e45005bf644a19538db2dba3e6cfe73a58d350b97bd01000000075263ac516a6a53ffffffff9035b64711b0897fa50807cebb1a029848b45e8285330820b765bb30c05492180100000006ac005253516affffffffa9b722d608673e3d661b6c81787d22daf2365ed06575c0dea7caf768edac32eb0000000008ab515251635300abffffffff1c92ab0a47b5db380f5a5e6bb902e3c8daedb6b64c2758381d458e20b0bb6ce801000000086a5352515263ab51440ed4be04b1fe110500000000036a65ac9d429e0400000000096a6a656a65ab00acacf23ae803000000000165f4611f020000000000ccbc00d6", "abac6aac", 0, -2019439413, "6ede91a98c82fbfe9e01017fa94d780e3400ff124bf341ab1aac478d72e1631b"], + ["2a71012a01137e762ef2ab8338a49e6c7d5e39a82d7a93cd9825084fc9e74ff57bdb2874da01000000085200ab63ab6a51ab92f51fad0390e43e01000000000351656380297e030000000000a9747a000000000002530000000000", "006365516a51", 0, -1928204193, "1c5c777e3f4f6ece9ac36bb82f9cd722ea8aa2fe59cb8e75ec40cf07a60f0aa4"], + ["d679dc53010adb8d4149f8890454389b2b1f7c0aa292a4bd307682d608f0ac954a7bb04a3a010000000152ffffffff03bf246c000000000007ac0000656a6aac4d7e1f010000000007536a52ac656552655bee030000000006ab65ac52005100000000", "00", 0, -1157831087, "b6542dbccf6fe1063f3a9195372a49a1afb6eb680eb8a0ea48567aa6562297fa"], + ["515f727c032df0281be10ef35583a5b177e68ca93fe6cc12d092bda362d0736c2426a2ab0b030000000853ac6a6a6aac0053350567917d8b0b283efb3188c2a923be1f0e33b029044d69b9943cf3eb6c14bd997ff3a400000000046aac000080e8617a36b813b0fcc4c33288c9c71e511284f9bff93e39fad29114ad58e851a7d9bf980300000002acacdfa494a9047884b40100000000056300526a65b812170300000000086565516a5263acab1502c2040000000006656a526a51acbfb9000200000000016500000000", "51", 2, -1356060564, "36c28d7c55e79a8de80bad02a94e838c101f8bd4abba7bf132e5283117fefb67"], + ["78903a2e0490cc1922e5ec6f0c23479f74fd47a8b2098298560a24af60e594b543345a8aee00000000025153ffffffff20e38a5e51356d9231c1f79e288e23b6c16771300f18d3d17193fae76de617080300000005525251006affffffff7f1a49c9fd11949bcb445cd002d402511338b847863ff470f56cbcfde22f8e5c0200000001abffffffff7892ab6dbc632fe9aaabe689dae2f7fe9b11d04274c97975818d2af6cfe2eccc0000000002acaba25da32601293e500300000000080065656a5152ac6a1f734cd3", "00526500", 0, 1824143208, "4a38cf480659c8e3e0a0c6f7ac099185838da325623ef5e777a85cb3ff1d0a08"], + ["088bf0bf02549d7f84d3d600c537bcf7f9bfbc1fa5957a3cf1d8e8b82b42a3bcbc6c7054c50200000000c3a13a84ad3a185b0e4cfe268904df529f83cdf4b93b2f09156a6737f9a1201e963eeab000000000025252e9be38ad0379afb20400000000046a51525172f53e030000000001ab56bba3030000000004abac516a06ed2de0", "51536aab", 1, 1279495884, "f0a97fc1e2bd3b8cf81ee918315c9756e43c9c322d72305b830d425c762411ee"], + ["cda93c7201c99fb23632f4c4104762b2507d78b9e3018c55d08f2b4c55e2532c0f16139db2020000000463ac6a6affffffff0373114300000000000352ab65461fe20000000000005fd0cc0100000000008a93c102", "ab51530052656553", 0, 1259030483, "fe1dac1323873c216cb42669a8401feb6fbd34546cecaaf4f5390eee24ec3fd0"], + ["dc0fb38f012956ec53f47f21ca36d3bf7c4f2febd39664e4c458bf766c36dcfad8a8d6b7c70200000003525265ffffffff03d9c9ef020000000005ac516300523d0fd0040000000003656aaccc989a05000000000751ab65acac000000000000", "ac65ab63", 0, -869480229, "4fe0b4835f5576e4527da58c572999082bab8b26817dd6e1c5c9278442f6f702"], + ["295703f9025444b0a51587c1c2f08096c8e2fe14638d37afd3d5e7271222d04f8d796928380100000000354ba48cbd0180c16c7a8d283c38196aff410e77e718f368aff8b079a5b127123093097b010000000653006351ac52dea2089f0441ce0201000000000865ac65ac516a53521ab79e0300000000096a65656a00635253653d82fc0300000000066aab636a63abca993a05000000000365516ab0ade547", "5300636a65516a", 0, 631858018, "6b69c004d271a4086f2a1f400a0bfa87b5f0c2e8fe79cdaf2a19d3957fd5e6a6"], + ["4fb96140023002203cd867e27c87fbdc9a838246d764d6a6c01df8be4567cbe5c4d6f31895020000000452ab6a53ffffffff6a4eadd1bfaadce931a51760fc63eea20e66ac4a1935d63d214a2df8fdaf9f37010000000900526a636a635151acffffffff04341529020000000000e96e610500000000076aabab51006a511cb074000000000001528bb2e202000000000097631c5c", "63636aac00", 1, -1987015462, "14910c3c47277c656af6288df9c358892a1f0ce304df598347e761ebbddc566f"], + ["3cc2f215046068d5b87e5b8bfd419513a3b1f4dde717536522c02cd4966be545ce4a391dcb010000000751005151536a531e3e991493df648ca51d8707956408357756999554252f0064463d1f6832569595f08bf502000000026565ffffffff66445b03708aff26726ed0ffbefab4bf7cac36c35b3114ca7d7bc0f0366158cc0100000008ab52526351525252d91e5ab7ec052a55457c979747f2a472ffac7f96c55a4a66cbcf5593ac0fc910e5d36c2a0000000002656ab8f5555a0236bcac030000000004516551ab8a3d850300000000086551655300ab65ab00000000", "", 0, -1994996534, "f030f4da83d306eb37e4e2d078aee9ea1a53eca41d4c90d6f25a91db2848bc85"], + ["67074d13027ec6307d8df5a0649ac9f45370c427ba6e9887a72d84676e56d642d6614c2c740300000001511677f7518fbcbd7f2794cd44fc8592ea8150ef8404c7c80541d7d4796b3957c223a86f9b02000000016affffffff04b7b0190400000000066a5153526a004fe62d04000000000853ac656a530063633d6dd7000000000003abacab9682bc0200000000016500000000", "", 1, 1233863639, "07991ef7cfe6afed4daa2f1fd28bb156370acb96ac622388f99f5db1f58a71ca"], + ["781b73f9048b9daf5c19169e907bc2c1bd30d0026850ad420efb366468b62634074e48c3270300000006520000005352765e22b56332000126107b5d9d7b8bc9c9a3135701b82da26269ff9e5414d34aea6aaca5010000000044aa0e48e046d5a1cafa471fff59394c70698d39ef725312bd0574005bc8c22a0f904f710200000000ffffffffc6e07dc1b68944451b98eb306b5750abe5d1d5cd77f654f2e4d28f96be6765bf03000000025351ffffffff037c01c100000000000152fc418b040000000001ab418cfb0000000000090053abab525152516ae863e3f4", "65ab6551", 3, -1249924659, "548cdae7106de5f26ff1d73d4d7d477d8ab45eadf2990f2d169e569ec6f4cc77"], + ["3c85cbd10163c4cd22208f994205608a85d2dbe95e073c165c92e689c9ecc42d6622731023010000000851ab636a636a6a51781cd6d1037229c2010000000003ac6aaba82fbb0400000000066500636551ac5b2e14030000000007ab526a5363656500000000", "51ab635352ab0053", 0, 118242006, "6ab8a4b0fc285a9b90a5405361438e28e5ced084290d0933db1cc03a8aa8c046"], + ["13e9f00e02cda89badc9d47ed6a9862a12889dfdd0ff372f9e494ad429cc8d145c1c65e92300000000095152636aab6a52abac8a6218404a21a6ab1a828734527034bf12c4d04c5678931f151975d1b5a1a23c9f4988b2010000000352ac63ffffffff03414af4010000000002ac6a34d8ac0400000000086a6a656a6363ab5276676d03000000000353510059c0b09e", "6a6500635200", 0, 1246873853, "c20fca49dc4041f90530184537d9c3a5b17a97677e50edf3bd5e5c4f007ccfc8"], + ["cb480a97042157cf627f32ccabde9b3aeb9567d365bcecb6ab6369cbc3b1d7e287dbf3387d0200000003006a6affffffffd62f1d4c71dd6a4fe3a37a0b0bdcd0da5a6cc9184472d159df361af92f136cc8010000000100ffffffffb77fa9cc4bee88acf1032cfe7d48f5c7b2462de1e9643c853925660eaf268c5903000000050063516353a3e191cef389e0ebe4ec26110dbe5d0b6f5ede95474c810e45df2e0c48a4b01ecd3dd6b902000000026300c418c016010f6ade0400000000075263516aab00002fb654e6", "53ac6553", 2, 1886048112, "987365c291085dfff57e33d0e9b117194d1454c05a633f902edf07f18b23fa76"], + ["50d71bd8040636efc5ddcd449e9e8ce08cd31a7ef2bd2175f9d520c86393510c8c8834a15003000000095165005352536363006686f9ed5d92beed5519f65e52e5cc5d4d6efc809dca21f483a241b35e5820c8d33078be0100000000ffffffff5d86d4c020bc3999ed2186a9568fb92b4d33552bd1a6f4472e6080790cc2bb0c0200000005ac53ac656a8c6b43f9f8ac22efbef6c4922185297ce94c4ff0737dc3398e97f0f723a3b2fc1617d6960200000004656552652f7d0a0004819e590300000000046aac6a53d04dc903000000000061279703000000000400636353abb147030000000002650000000000", "510065acab", 2, 590108137, "a47f8b941da584bc131400c59b9896568aecf5c9b269f988ce5033df5650a096"], + ["d6ba052f02ce15014dc9f9f044f85ee77849f1165ca3284f95d9c4aece00d57eeab694f06c000000000300ab52c8767f46e629502c88fdb7d4d800c114661ecefdbb69eeb4d7617d0fbf95d35f2e2d44bc00000000056aacab0063758d771b02e9cb6a01000000000852656aab51ab6aab909a4304000000000463ac635100000000", "ac0051", 0, -1983268539, "f9a609cadcef503e0969c58acd7076c81a621e20c822805fa54365f7e6028c7b"], + ["b0d6c80f03fd27e224e6f21ef6ae0586582f1a9eab961791486a6b619166cf3ecb09d872e201000000035153acffffffff27f11680ac591ed4fb8764ff58253425a1182c8d55117cdaecbb4d98ed18b8da000000000453acac513cc6294e7c4537e2c107e371b029675b51379268db03c7755a582b12fc806bfad1011dac000000000551526552634f10498d036645e2010000000005005100ab6a0da4890300000000015371cbd8030000000005636352530034438b98", "52ab63", 0, 1428768491, "abef0e80590e31d592a45f2b7218a45bf920c7c10b92cbd22fbb33f83931bc36"], + ["21592b0102be17dbd38f018b8eed360aae1d82d3b6c911a252e8dbe868f8cc7c77e4697e770300000008ac635363536a65acffffffffc6520a3f295e286a998ac9de646ada29e3eea9fe1d77123c2d79e2330a13c61103000000060051acac52abffffffff01dadad7010000000005536a520063b091768b", "00abab636352635151", 1, -21717803, "ed38370e29946f910783bbcc653a31cc33261a9de842aad946bfc68a9e146e5b"], + ["65eb7caa04e9c1b659c0a84d735936501c761fc70c3aff16bdc40402753d13d8bc5ec352d000000000026500ffffffff0105a7d2e445acd85312cb9493033cdaacbd3e4e128966647f52c29e5abda4d703000000096a00005152ababab632dad0c71a30064971e27fe9135eca26d3ddea2b97f16c32d3c204391e02c50b5a07040e7010000000765ac5165ab526a2964c729a9e846cf9733cbe3e6ea44eb470627ae8e6c693fc301de85a28f0cd772b8bd7a00000000004efe0d39045f5a94040000000007535165000000ac7922b3020000000008ac63ac65abab510065911c000000000007636351ac6a53ab62474a04000000000000000000", "ac52ac6552", 1, 2105988321, "6be92881ec88e3cd2aef64c878f4ce47cd779df9f38bd4a7873bb2b1c9e35ae7"], + ["9428d44d0356e8eff8cf85d4845533143bf6900f9901b53c22cc02d78cde4343167d4f624a0200000006536551515251d4b88b15b92e23bb2c4f55123f27d7f1cf52e5ac3a8f0797a177ba2a2695a21fa47963330000000005ac6565635244c0b864fabc6ee5a330f0fe88fde7552c4b646094ff6f419819ff16826a1a89edd8bb4a0200000009acac510053535252ac8f9421cc037abf45000000000001525a20070500000000035253ac4a676300000000000952535163ac6aac6a636dfc1a60", "", 0, 1108098765, "5eabfa4ba2af418221083d8fa0f837dfe04d94bf3275e373cdc4c26412f32e36"], + ["c9d3c8de03f65eb4a0c3ea7332cf917991c77af567fbfbbe9b32519a30d4ca160f1eeec8440300000007ab5100ac656a0005e6beedcf43c40eef19792bbc9698d6783f837de9be6ab2df19cbe0c53f3fa541748ab00300000004650065524cf5b6585b5f5754e52543bda37f636a9a3297b5b8d49007e1a09ab0c1797ccf9d02172f00000000055263abab651657f340015428fc030000000006acabab51516300000000", "636a65ab655152", 1, 1726532583, "e824851ce0226ee850d417db1006417d6c62b71625425bc60376d0fe6f62df06"], + ["0e7f90a401a6f4bcd3ac039b4528647745996c249ce35eb1c0b522b078aad5954a29944c800200000007ac65ac63515363ffffffff0317fe4d010000000005abacab6352f5665e010000000005656a000063e983230200000000036a656a00000000", "5263", 0, 2103220685, "855f953a66d9370747c0a7df58a73d7447ed39e085bbdd5ac5a88c6229e9b303"], + ["373bee5102714bfada878bac73752cc924f907732b726998d81ea56a98d97742bbdb9867e601000000095300630052abac6300425863dfd5cde71cf9198461ac03a95d5926ae62d3e3fe49d0338973679d29ad679a9f61010000000453526500ffffffff018f4a43040000000003ac525100000000", "52", 1, 934602099, "60b2b48f0639d3c60c5caeb743ebfed68b0df14eb9a78ac815e137969c79fe2e"], + ["913cac6d04145069943cfa7ae6ed527c552af80769f6c417f3e44c3ff9aa8a23bc7854873f00000000085165ab65ab515351ffffffffdd4f4a41d45d9f7d69a8b39d503a509c5d9606c8c3ebd73a6308adce13dcc12c03000000050065ab5352ffffffff003796b98f6ebc10ef5524d29571b2f3868c71a86669d2d96e463725371586e60000000007510065ac535265ffffffff99e4eb3a624d903aec85cbb37e11b7cd1721dec9b800ea360f064dfbfdc5324a00000000065363526363abffffffff04b45d1a010000000003ac655276e19b02000000000853516300536a52ace95aca04000000000265ac6996a1010000000007ac6a535252526505ee9ab4", "6aac00acab", 1, 1157362925, "4c9d6a9b875a38f39cd9db4bcf6320dccc9f5c280c67a5fe47831ce5bea947a6"], + ["539d640e0416e7696be0d16f1e58fe12dbb452667ebeeb5f26417e13e077022910860d62db02000000036353ab59c537ba61e9f7fbd3b362afd1e3cbc3a29480134a0bcf459ae8e566efddad4d9613058f030000000263ab215c0c96baa1fef54e798148024051bf92e439047af6b4d3a28cf542aa26b17c52a01f5500000000085351525353656552ffffffff63a38a5d077d925d1ed113a039b6b9839d463dcdd927c47a20a4c4385fa2251e0100000001ab5313734e029f084c03000000000351acacd5ea6c0000000000075351ac65536a6300000000", "63535353ab5165", 1, -423892244, "52c6ba51a49740c85d5320c2d6b217734cd024eaf46206001a82aa7be0119400"], + ["cb0a35b704685b0ccfe5f7bbcb1af141c0501324ebe024c66d77e2f2c532cd7bf5d206906b0200000006516a6552ab533bae7043e123ddbbfbb0d7b120fd6584ebf1b923eaece73e8023cf66cee2c829f4cfa324000000000853656aab526a6551d969de4aeaa0b9ceb412aed8aa1b23f200dfc251563bc36bfcf4a5bc477cf2e0b2ebd36c0200000007005265abac53520a478ac8c16978a028383e7981566b5fd74d27416dc36556dca040a33a63d05bc30a461d02000000066300516aab5397ca07a3045dfc04010000000009ac635352ab6a53526ac9c9160300000000056565ac51520a41e304000000000952ab536a63ac00ac6a9d9c4e0300000000085351006a00636365959d68e4", "acab535300ab515251", 3, -2001499401, "375c69cbfab134cd62a709152f8a73399e3b1ac678b446ab4beb68f1a70cb33c"], + ["274ea72e049cfa8ffe67263962866b22c45abc044ab8177ed3d8a4829cf586f8f9667a75320200000004ac516353ffffffffb0b199b11da36ade37b9c72ac57fe65f50eae0f3f22e3377aef23173da92e3380200000000ffffffff7646bd5f06435bcef311e0054702564435a9863cbd8381233505df3d72e7402a010000000953ac5365ac6352abacffffffffe2196944c87bd9d9de044ce8cfdd64caa184fb66072bbb4caa9c661b7a9952ba00000000055365ab5100c37da9c303627d4f010000000007636a6353ab636abf5f530300000000036a63aceb186b04000000000563abab63518f85b2ac", "535165abab63", 1, 1081584497, "aee3e4de289d506e54fb3dfb83591ad0ded41ea361a7bb285f4765af1477e5cf"], + ["0f1849cf03adeb47182859495ee42833a14bf2e67f76a4340d6d970073d306f5ab67c04710020000000700525151536553f075bc2c81828abbf9ec524b913215e6fb4fef542c4ae916b0eaeb71699c3e00be2750b501000000025353ffffffff8981402734fa8ee50aef3e5531a2124bc1ac706b1a37b9d257d43e4ab88062770200000000ffffffff03074b5b0500000000020065840d68050000000000fb7b4d03000000000400ab6a5100000000", "5163ac00ac", 2, -1592031925, "d45cec6708463aaacf868faa0abbc98eb29c332952a9500e19861a4250e4cac6"], + ["c135ccc5026e138563b23c2577900d9c2a9d5eb3122f2ab794ae0843c0fa1b8b0783c0d5a002000000036a00abffffffff6821421cc450d5566e39b6a9c3c9aa4f617b364a84850b5a66c6c6a8242cdbba020000000963535253ac656a6353cfcc5d520347afab02000000000951ab005353525251517ebc2c020000000000d85f8605000000000653655100655100000000", "5300ab6a53", 1, -8720018, "23b8fe8ccd89d7f79e4738bbfeb01c3edd169db9e5d095fc4c7c3c67dbb75096"], + ["f5ea4b4d01e602ab71cbe8fef5e07829cef8b2fbe5ecaba7fe282820d967920d99d25e4b3a0300000002ac51ffffffff0100606f040000000005ab655100514f6193ff", "6300515251525251", 0, -1792715658, "83558039163e9cc52aea9cf69eaaaa92f910100a7b3dbcf4a41ba914df63e3b9"], + ["017b4e580286772464f163b250ccc77ae8fb4077df7e87085464c32af40d1099c283d3ff8c000000000465525152ffffffffb93a3b618d05d257b967e54b58562c6bcbeee7093b90b497038fe4daa83dcdd60300000008ab6a6a6500510052ffffffff046840b2050000000006526565636aab96f7a2000000000001ac1ed9e703000000000565ab6a000025bbda04000000000251515c71dff6", "6551", 1, -1054965037, "51c90ed06486c5d54e1aca8d25954dfaf1d4ee8c16f9908d730c22f1bd7efb2b"], + ["ae659a0504aaadc6517b40d466ac262ffcf8451335c4cbe94a71a6a458e431b6dbf964452602000000026352ffffffff70ba87d3e1f0b327e3be107f334f005cf14805bfde8d6073be866f9456b037710100000000ffffffffd8c0e31950a3e52a1bda3adae7b6365cd10c24ba41a6ffa238728938c9dee8c903000000086552526aac6a6a6a06370e293d0f80da6b854cad0a8f6b79803e3d64fd52d09891f265d51f94e0c9204719b30300000009ab636a525351005163829c44ff035fa82b040000000000c4aae900000000000463ab525283aab401000000000652ab5363abac00000000", "6a53", 3, 1321030904, "4c6c2bb07e9d10b60cfddcd140f0656a0237a4cb1a1ec120b03f471e9e631a48"], + ["fcb68c6c0334ebcdc3e18f4e37b8e2759cb9901fd944f28b1dc41df9aed080207795b79052010000000151e652a2e23a810b144aa94cc653a6dad385df344c3ee87d6858ac579089625df808903663030000000400516563ffffffff27f7f3aa6af6eabb3ef33080b721421f11c4e127b856ef1fa1032aba2f1516140100000005ab63515165bb7a04da018efe2a030000000005656351005200000000", "5153ac51", 0, 1831473613, "37acc656f877f0a190b35b795e39175b15290811f88ff8df319659018fb31fa4"], + ["4367ff3e0161547a4d213a471019074f5ab1539c4d1bbd1311af164d16f5fd3531f95b3baf0100000004636a6a00ffffffff030132be0400000000036363513b7c7e0000000000026a5340ea86020000000005ab53ab6a00093d266d", "0053", 0, 1371271919, "47aacc8d17ca60728bf623ae7b72c7ca76199c5da40246d8e5207996fe9bd58e"], + ["46fc864e020e117783646102f12456e4306b9b616ac40053e53a6eef11d6c06603bf94270e03000000085263ababac636a63ffffffffd75dc9f5c0408dc9fd0fcbf32ea2339b930a19f8eeae9b517b4717f07666a8a002000000046a650065ffffffff01de39c9000000000006656aab51acac276eb420", "5363530000ab", 0, -669247627, "accd1e2e361ac5f59a5d7fe40f6043b96a862ee1956f38bf0e7179886baf3c22"], + ["2f1cae2601ec7747c366aecaee0ed7f09c778a2c0375cf2c428dc6bef9c861121e13edf266010000000163ffffffff020ac38b02000000000013c1a70100000000045265ab63ff6e85a5", "ab5100ab", 0, -626791975, "9fa40e83b435ee66ac225b8bfbc8ec9d5418844a845ba63104d8f644a09c0117"], + ["601213c304ec40af6db4c271ab9ac707f7e9d7cf91bb0ee56ef1efc498f9db7b8e593926e0030000000965656a5200656351528118b95b142247f51f68b6a58ce89344b99e4f04638cfd027782c308520fefbb83d213f503000000025352647319242b28e29ed7342aeb9e63dbd79f86f7fe0abf2b9d076687b7ba1569370c45cf480200000005ac6351acac7bd40e18c341ae91f4c1eca22f85e7f8ec2291cf55024c18d3851e0d0bc9b6a729711aab02000000020000ffffffff014e34570500000000046a52ab6a00000000", "ac6553", 0, -607886271, "31c8715de916bf007c5efa77793d5614b1ca36b184bdb6df49b92fc0ac7296d0"], + ["6f83126f02f6a12d221819bb9ffecfc2a32a11d8f42e1789093e5ae8c46cb0e8e67ce89d6b030000000351ab53ffffffff230dc4406d6fed9a99c17c4557fbaed4bed263cd1d3c1c7799dab0b825fc108a000000000752630063acac53ffffffff042359240500000000016566068a0100000000026352a961b10400000000036a6a52cd49d6030000000004655365004fe533a7", "53", 1, -1950349580, "f0c5101e0c0986e0395fd75bf8c3c0574ac52a0004f69706e172f2d5e2a77ab6"], + ["09138ee8011ba2f64a6a770ceefe912addfa1d5037f9277701a2317f0ee16c930a56fe51e001000000085100526563536aaba826a9c302bdcb3d030000000001632fe819040000000001657f817581", "6a", 0, 262738245, "ec93951a2d089cdd24a64ea0c2ba08d4a182b9230c15e30249fe597961629e4d"], + ["2fe513a301a6d2cd80c95cbed7c58f016fcfdd712a92b382e008b86b7aaa1ea0f50a4754f801000000050000526a6a22c338ce02e228b3010000000009ab52ab00ab656a636ac5bb480400000000045365516500000000", "51acac636aac5200", 0, -1981214367, "7fa81037d95fe1b7744029e242cdc4753095e67ea71821e7729a32f3ebaea7d9"], + ["6d2f6943045081d01f116c587b6c37a5c1e40b832ea14a01c8297c057527edec64dbf397d10200000009ac656a525100515365ffffffffe72aeaf1cfd3ffa9123e52fce433792b5615e2da30f582622a7d9c1b27ca4a770300000005abac005352acc2a3f654ab9f28e279e8d3f7814e4847386735db69ae7785e875d83c8e9d4b7921d4af000000000652ac51ac535102806d37b691612ea7560fd07470017dc397f41a36e46f61af61b01f8a9febbd7b2dbedb010000000252003c6b5c1e04862a9b00000000000353abac3e6df5040000000001514eea3b0500000000006c8c780100000000056a516300ab00000000", "5165ab515100656551", 1, 332136022, "ee5c8991664f8608cbec1278741b02cfe99a3065a7baea9a4960dd1b9624fb6b"], + ["e18151ea018a65efcc500ecf43811b17bc2d9daa782ab9a93e2037f07847570c4ed58a41c10300000007006a515352516affffffff037d9afc03000000000865515100ac5200abfeeeab030000000000eb94af05000000000252654b7580e5", "65525151ac636a", 0, -23932721, "528d01848ae1fc06d6ef30df7a392261108f72f0befb5cf4ecc880846f7d436b"], + ["4d0356ab041c8d12fd4f1826680f9c4b94325dcabfcce6b5224bc70da4478cf14c96c3f2560300000000ffffffffb36b77d95290d42dbb5bc10fd75e78bd0f66cb7181ac03bf066e2293232b9d58030000000465525365ffffffff410e69d1327f40e4384f05ec5c8792afb54b4a43ce0375b2c6448af721c2da8b000000000853acab006a636352ffffffffbd1436f84b2f6496341d4742f99704a4a71c26864ce5bb6be6962b57fb8da0a800000000096a0051ab536a51ac52a4ff18cb0234949e020000000009acab63ac51636a0063a354130100000000046552520000000000", "5163ab526353", 3, 207271499, "140fa2f889f07b19bb0aa09324341dbef00f1ee29557be0ae82978de80164cfd"], + ["a879873c03e2b3866ad77109fae496f50a8ea6bf7547c12f7c66aef3a8bf9efef2e990af1f01000000056a006a5163ffffffffc8c56a2fe378cfe4fa9c26982e93b930d59c6eb92b60eb473186b393f64a397800000000056563ac51004cc8c6cf47a66d039d8963964b81d1f755b414bb7a1636c86c94c53cc7495634078ca7fb010000000263630339d61601b9f6a201000000000665acab6aabab00000000", "65006363", 2, 1251788744, "a1030f2466a12612c7bfe684d03aaa49a599655e3073ece8d6c8e653c9200457"], + ["bbcca75f03edad9eb341116d44b02388f043883911bede0b754c766cb3cf2d998ac7154f6c0000000008006553ab52655251bc20695a0cac516d1de0947cf601b71d2f664f4abb9907a289388d7b11ad9610f2fdd086010000000263007c227ebe08357254d5a0a2a59031b06de7f6e160eed15fa23c17992d375418bf1b71dc0103000000070065ab53635263587aee330389fdfa0400000000006d0082050000000004526aab531193d30500000000095100636a52ababac6380be9d72", "530051acac", 0, -830030877, "727c45d5a0d6c7af1806995533e70ab1d2845c507797aa90765d4fadcd243f01"], + ["80965ba304d8bb710cfb31cf6b7944c618205c1722f627f7418ee40f01ae4d63924edb7ebe0100000003ab52657bd5eea0c2839723133d8ca4a08d6e10eabceafb9d8e494ece4c1a3d3227a4c2eb170647020000000400acab520066a40ac8b2a800e3ad0a9021c1d2a46c36b2f50c6e94f096dea22bfac1f478706e5b62010000000600656300acacffffffff7054e2c8d7232b19f1a8ef0d7b88584d7da6095713fac01ea2acd8ddeb5180ba000000000553516a656affffffff01a13314010000000001ab4c060054", "63515353ac", 0, -886608040, "adaf9cf52391c9179da1d404698d80e9c7a7520f18c8fe2b1db5a6e0e7f6022b"], + ["21deed1802cf38884c9a41b2228a85e8ec7dccaabd11ae2ab3bc2e3c9eb62ac55b697b96c500000000000da657406542c4df16aae4569379ec8b04dec8a4b6f6a446c0042d1913261f760aded158000000000700656aac006500ffffffff0347f49c00000000000363000016da250300000000036500655701ca02000000000200ab027ec3fc", "516352536aacac", 0, -1107794725, "e8159807b6efae4c7c8badd99d7b8fa02b72048d83021bb18f7c3fbc6b7c68e9"], + ["2ad0190d023037fe32237db60039d200c43f33b18359b1ef40ca92e4cffcf8ce69f59c96360200000006006553535251ffffffff38cce6ba7d3cd35bed4f5cc7130853cb8bd16cb83f898539d77f6076fd488b0801000000046a65ac65ffffffff01373d400000000000045200535100000000", "51530065ab6551", 0, -1699952696, "42297812e9f96a45cd2631d3bf211a68482d8d0c9c02a373d76e33dd6fe2107d"], + ["3aae4cef03a4faff31ee0439f94bc8f35760104094110d0e1412293c8302e8b35ad59dd229030000000863515251acacac632d95e2f2d6fd1912a37bc7025a49a5c8839bc39327aafee2c1c329ced2fc7dccbf0e56b902000000040065acacffffffff5d293f98157a0d9b558396530656fdd81ec5993b3d64735a8ae9bc77eedd211102000000016affffffff038f56f800000000000000d7c2040000000007acac5252ab5252e7f7fd02000000000000000000", "00ab6aab5252", 1, -710638099, "ba7a7c983dbef0ad0d759c183f7e5c592efdf006206bb47e501cdd2e32095a83"], + ["e6d5aa5204acf45d76da687108cabbc9e1f6655b9e345eb007e41115c276a266f72030945f0300000009ab5163ac6aabac52511bc48c7532b89b3497200a45bd971853ecff1d82cd251b1e62efda61a85fef82f13d1c990200000001532ebd30a802c29352d58234c7af1b2485ae4096a277cae033e4f6bbb949c7bf9a1604830e030000000663006aacac631920a1869273b72b95d998e94e608f86123476d89ae35cd9f0a8345181d26ad1b7a5e0da01000000026352ffffffff029edeb20400000000096a0000526353ab00636e9069030000000001523689fcd2", "ab6365ac", 1, 382904573, "015b322421e9ac1c92e565647b8a4d94df19421f372c42d9d5ca43c8f8263594"], + ["0fd830a60402435a4e606751bba939c5f873e9539f6e6dcfd0e2610f7277e891b89157f036020000000453ababacec4dbcb4bb485d2a2e77989f23bc5b0a5d56930c78f50264d922f7e1bc68973b6eae686502000000026a00ffffffff6ad076d9bf26d9cdfabe283d49092c1b5fe36e4034cbb2924ec837d43efc1a8a00000000026a63ffffffffed9ebde767511cbed4c24311a1a6319773a3798497a69496f3580aa381db547b0200000004ab630063ffffffff03dc40680200000000020000eb1429010000000002516ad69c520400000000085252ab656aac5353f87e0c5f", "5352", 0, 753290455, "3be258efd2bad7502e3cd20d56eaa56d2ad7f78a4036f7e16430894dbae215d9"], + ["841b0c55044dc39770e2cc27bbbba820588b52d8506ede8f0747f3653f313786adba809c9f0000000002516affffffff2546a098e242703bb3c0ef8771c2650a2685697761440304895acb2bc2f40c69020000000465ac51ac45b17036b9e8052caa4cd7bf6f10ecb19394284c5a05eee49884adabe1d8fa54aef59b870300000000ffffffff25fa4a2ad034b465f9a6d7f9f26f78e52f335fc01bcc3b12db4c2b6600c9e8310000000000b336501202e161ac0400000000066aab63516351ca99da020000000007635100ac52525200000000", "51636365ac53", 1, 1430473336, "02d89b70e3498a0cc66f21e456845ac5f380906ab0d41ca87ee7ab8f02726740"], + ["832d8abb01c01c960b7f245c881ff1c7fba3e333f4be825938a7ebc06a1406511b2c0526f70100000004ab6a51006548bb5003e03684010000000006636a53515353409b7e0300000000086a6565abab52ac529be5700400000000015100000000", "656553", 0, 442282446, "d059258ffbc27351a298516bbdc69f16d71762a155c70263a00f16e0bcf3e0e6"], + ["9f55385e033dac2243ec8adab367f40a0cafc222f26c2a84a9d62ae65f3141d0e7eaea352d03000000046563ac6affffffff19608a5e38af7eb99521baf227a097069a4d23224ce804570a93899ac5bb795000000000085300516553abab52ffffffff722cdfebb4b7797add063dbf8f8185ffc5f56ef63e80c708d31a5a9dc7f32dde00000000015217cea20a03ee25dd040000000001530ce711040000000004536a5253a07f0c040000000005515363ab5100000000", "", 0, -507882013, "e00897df53288472054e6410472b932ce3e525b7c1d5734f372ee3e85ac05d25"], + ["7980273c040bd904fee13d5c4384d3c82b875126f187693fe028ffd1673766dd11423ae79e020000000153b1c0cb99f1ac878277a9414dec5b02d0b9fbf855cc915e3a20f497768a4796c4da8a788e010000000300abacffffffff1f42d400bf325ecc618dd71a81ca039e9c9ca575b413a405f0ffbcd6e27008ae020000000651ab6a63ab51ffffffffbde0ccf3a86b81056083dbd0e1e77c408a769e02e537167a04440e63280e182c02000000046a006a63ffffffff01cd5f90040000000007ac63536551515300000000", "536aab636a515253", 2, -98265898, "02120c4fe543ff011fd454a2c01bae052a94174551e9d688c6dbfdde30bd7eb6"], + ["ea30825701ab8742e301d649dd739ac4916e8de381afca17982f8f24b950487e42f91cc3ae0100000000e4fbd0a804e0cd460200000000056a535300acd630e804000000000765ab6365516a52d518a403000000000352acaba3e4b80200000000085353650063635263b6ce90fe", "6a", 0, 1322978155, "4b725e82ec699c4c8f91a0decfc7ec25aee94353e7faee658e968ad748f347ee"], + ["d91ee3f602840eaafaa29e1ae97b87b7c23cfc2595a1c31478433b106e4771d6d44bdb4578020000000853636a6351ab51518f47e12f730a8e84d619a5321cfab7226acbfeeee653e3c955ffff61c521bbd94a041734000000000451ac5352ffffffff02befb870500000000015303ea00040000000002650000000000", "", 1, 1116586867, "9b506b51d4d2685b22aa40529a227abdf63c246ebbffac3b3aa854f30c45f5c0"], + ["8581f07c04111b3e21195490842a206cde4f3474d3fe437ab6f48d178ddac3254a744cd9240300000008ab656aacababac539a0c32b2a7d46a20975c527a7f880ca0c0e347287ad96a715c22820e375b7278a061d7880200000000ffffffffc8a7899054df65e8939c5feb43497086c1c86ad7020512e7cc8590f10d6d718e0000000006ab635151536390bc96d56073a039fc9a78ece69336316f5fd74886f9b8f7fabe9559c8299594b751200400000000025200ffffffff044be0cb020000000002006a4bb23b0400000000065263ab6563526fe5b20400000000030000004d52e10000000000035165ab5463affb", "515251656300535153", 0, -1620894655, "94448e897d6feec29d0ebff8630273fe42aa188befff37dd776108b03bcf28e2"], + ["16df8be4044fec2f5503292300a2d5ea4944c51b4003f58f90d010426c54b925babbb352f00100000001abffffffff3febe6711b3a29ba1a274db6cb75b494b9de200492f16e4765f672a5a323ca4c0100000001aba5c5931867cca78f8421e3900b1ac26fe63b127ae3323c8436ac6a18910a4bee069d67b8020000000100ffffffffae460b8a935a8a66410f290acfb7a318d93d63cd8759726f30dfc2cbb155ce7700000000025165aaae539704d264d5010000000009ac0063536500ac6a510d9f8902000000000865525353006aac6adc13d3010000000000775cf80400000000076a6aac526a63635d624e57", "5353526aac0053", 2, 1263832401, "90b2dfc8e9635f08febe2bdeb8bc5bed76f8637561910b4ebf9be0048bfd6bdf"], + ["a97515da0217b7dcbdc6a465904ccb048163a4f1605a38efddb92e1945c0f05c8c579ba80c0200000002656abf34db26b3ec0f6e088c1a5c4d399daee0ef8805f70fecc64a0207914712e6fd0762f54c0300000000ffffffff03af17450500000000070051acababac6aeb6055030000000008ab52ab6a00526aaba1d294020000000004acabab658ca1d8d5", "525263", 0, -493530754, "80396ab5b902a629ad897e8934a3141188f4117e6e271c6fee43c33f8ed9c667"], + ["727df1bc02732098cf479bb0ea55eceb3ee74f14f2005b030a3dbccc6893a3e901f345c32e02000000056aac5351511e30dba85e1bbbb9b79e12764ac5c07f0f26e23b134088fc1a7f0dec841d1e32d094caa00200000000ffffffff01e4661405000000000963516563ab00ab525100000000", "52ac6563abacac00", 0, -1413124794, "9168096d1509a7e11290920b90a44a318de78f2ee660f4387ae2a7f6b21d7881"], + ["5887d5a004f7486e82fe449c1e43bc680d49d0a81a0b6d196ea19af8d82eb0042c3ea6bfea000000000200ac7893c4acd9d2bb22ab7b67be225612db84499e569abb4bf702c76a634dcfbe93b3de08cc0300000007abab6a655352539c24fa4a453f435bdbfc91192c3ec31445e5d2a3dbdd6b16e03783ea9444a5366ff1201901000000026a53ffffffffd5bbeb6c3f02236250533ed70c3bacecf90499dde7e69d5488fd6f49d73a949a0200000000a6b264330316e6d70200000000020063d75f650400000000035151650b314a04000000000565ac53ab5300000000", "52536a6a0000", 2, 884599520, "6df2fcba35fd968382140a63cbd34adaa04b8a9e51cee3db3cbccb59f4333380"], + ["063ab70c0468abd68e99dcb0ee7dfbffa2d7edb5d5de06d0516df3728b97add2da0fb0c92d0200000009ab0065ab5252ab6a63a7bf00f58d843d6bdc0ee2bfa1665c136accf912c2144e0fd8afd23a857cb785d3c69ae30200000008ab516aac000053abfffffffffb02e2ab3937feb72b400664096037d2a91027ef4151a0e85af7e872fe9d70610100000004ab005251c0684e14d2c095584bb3d34284437c9cbc85300f972425976115002ee85f09056884987302000000085151636a00ac53532088c61e033b463d0200000000075300006a5151acdbb6ce0400000000016a9eed39030000000001ab7009c9d5", "ac6500ab0051", 3, -358045089, "7b5d79028b487a15b28745f488f2fce77fbe4c9874ec669dc4226dad6adddb01"], + ["a429576a02d39a01bbbcec2121eed27912165990b159405b1b0284a662cf464f8c7d0239cb0100000005536a526a63ffffffff86a4c286fdddefa3f45f75530d8a3cbef8d07ea5aecc54a6445b5ae12f2fe88602000000056a63516a65ffffffff04d5a3530300000000046553acab2f8952030000000005acac63ac52483d0b0400000000096a6a6353ac6a6aacac73cee202000000000565ac52006a00000000", "0053", 1, 662152413, "fe502a3c169f960f4e0f8496e562fc9e0fb4e0603110be61db8d4857c077f8dc"], + ["a54f96d3034153323bc6ce5ba97793b0d1032018be7ac6816155661ab1112990d0789741ec01000000020053adcb23283024723d4a904a886e842bd6df530a98e83465e965cfea3077ce69c81c5ecea10300000006ac6500655365fa890589f18427b0493ab412fc4e68c862f672b42740cc046bae47bb41bfaa03629753ed00000000030052abffffffff038af457030000000001657e0e360200000000056565abab65a6b5a7010000000002ac00c0fb9b98", "53", 0, -784333341, "9dafc80679621e60b3026d42876f824c693b83f78e83438c3a00acec5de62ac7"], + ["3e4b3b51033c063f6959a651b10099a3ac4ee154bcfa7e69df53b26d910bcf3b671b344aad0000000009526a6352526352635114aefc0461ba28a4ac0e44a7dcfdc05caaac5d205f927293e60cc084cd0f32bddc5e3b660300000001657eb2300167f2336482567d88ae829de00bf1146c7bac563d99c2fb74662226d408fe104000000000085352ab00ac5265528ecdc28303d01d580100000000002b073405000000000763536563abab52557be5010000000008006aab6a5163abab00000000", "5253", 2, -397094790, "5864832f0c3d7c422abef5c287ff4d84b25b773c346a9cfdf125c0fb6105871a"], + ["e80d62fe038e6398bebf2ebb6fc527abdfd8be541ad05f5dc3cb25eb87a937eea21f136bfd010000000863ac516552abab6affffffffa7d0b2d930800fa6126efab87cb339ea79de3b755d2d46626af48e229f4dc3650100000007ac65ab52630063b4f49a445bf63006d2bc0eeb814b4ce7774a7181e73f1eb735a932ef9f03196a383e68cd010000000152813f784403970e2204000000000056b04c020000000004006aac51ccfe520300000000046a52ac5200000000", "65536a63", 1, -1835164180, "69f0044c089789b274e5d50b240b763aaf98916a311d4fec166b3751fc1b7ca9"] +] \ No newline at end of file diff --git a/src/test/data/testblock.dat b/src/test/data/testblock.dat new file mode 100644 index 00000000..b1149b24 Binary files /dev/null and b/src/test/data/testblock.dat differ diff --git a/src/test/data/tt-delin1-out.hex b/src/test/data/tt-delin1-out.hex new file mode 100644 index 00000000..42ad840f --- /dev/null +++ b/src/test/data/tt-delin1-out.hex @@ -0,0 +1 @@ +0100000014fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000 diff --git a/src/test/data/tt-delout1-out.hex b/src/test/data/tt-delout1-out.hex new file mode 100644 index 00000000..cc60c3fa --- /dev/null +++ b/src/test/data/tt-delout1-out.hex @@ -0,0 +1 @@ +0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0160f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac00000000 diff --git a/src/test/data/tt-locktime317000-out.hex b/src/test/data/tt-locktime317000-out.hex new file mode 100644 index 00000000..287f420a --- /dev/null +++ b/src/test/data/tt-locktime317000-out.hex @@ -0,0 +1 @@ +0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac48d60400 diff --git a/src/test/data/tx394b54bb.hex b/src/test/data/tx394b54bb.hex new file mode 100644 index 00000000..33f26cb4 --- /dev/null +++ b/src/test/data/tx394b54bb.hex @@ -0,0 +1 @@ +0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000 diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index f01ee06c..c73875f1 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -2,63 +2,258 @@ ["The following are deserialized transactions which are invalid."], ["They are in the form"], ["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], -["serializedTransaction, enforceP2SH]"], +["serializedTransaction, verifyFlags]"], ["Objects that are only a single string (like this one) are ignored"], ["0e1b5688cf179cd9f7cbda1fac0090f6e684bbf8cd946660120197c3f3681809 but with extra junk appended to the end of the scriptPubKey"], [[["6ca7ec7b1847f6bdbd737176050e6a08d66ccd55bb94ad24f4018024107a5827", 0, "0x41 0x043b640e983c9690a14c039a2037ecc3467b27a0dcd58f19d76c7bc118d09fec45adc5370a1c5bf8067ca9f5557a4cf885fdb0fe0dcc9c3a7137226106fbc779a5 CHECKSIG VERIFY 1"]], -"010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000", true], +"010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000", "P2SH"], ["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json"], ["but with the signature duplicated in the scriptPubKey with a non-standard pushdata prefix"], ["See FindAndDelete, which will only remove if it uses the same pushdata prefix as is standard"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], ["Same as above, but with the sig in the scriptSig also pushed with the same non-standard OP_PUSHDATA"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], + +["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json"], +["but with the signature duplicated in the scriptPubKey with a different hashtype suffix"], +["See FindAndDelete, which will only remove if the signature, including the hash type, matches"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a81"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], ["An invalid P2SH Transaction"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], -"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", true], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "P2SH"], -["Tests for CTransaction::CheckTransaction()"], +["Tests for CheckTransaction()"], ["No inputs"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], -"0100000000010000000000000000015100000000", true], +"0100000000010000000000000000015100000000", "P2SH"], ["No outputs"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x05ab9e14d983742513f0f451e105ffb4198d1dd4 EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e03dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b571e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f0651c7acffffffff0000000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e03dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b571e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f0651c7acffffffff0000000000", "P2SH"], ["Negative output"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xae609aca8061d77c5e111f6bb62501a6bbe2bfdb EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d4830450220063222cbb128731fc09de0d7323746539166544d6c1df84d867ccea84bcc8903022100bf568e8552844de664cd41648a031554327aa8844af34b4f27397c65b92c04de0123210243ec37dee0e2e053a9c976f43147e79bc7d9dc606ea51010af1ac80db6b069e1acffffffff01ffffffffffffffff015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d4830450220063222cbb128731fc09de0d7323746539166544d6c1df84d867ccea84bcc8903022100bf568e8552844de664cd41648a031554327aa8844af34b4f27397c65b92c04de0123210243ec37dee0e2e053a9c976f43147e79bc7d9dc606ea51010af1ac80db6b069e1acffffffff01ffffffffffffffff015100000000", "P2SH"], ["MAX_MONEY + 1 output"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010140075af0750700015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010140075af0750700015100000000", "P2SH"], ["MAX_MONEY output + 1 output"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510001000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510001000000000000015100000000", "P2SH"], ["Duplicate inputs"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x236d0639db62b0773fd8ac34dc85ae19e9aba80a EQUAL"]], -"01000000020001000000000000000000000000000000000000000000000000000000000000000000006c47304402204bb1197053d0d7799bf1b30cd503c44b58d6240cccbdc85b6fe76d087980208f02204beeed78200178ffc6c74237bb74b3f276bbb4098b5605d814304fe128bf1431012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff0001000000000000000000000000000000000000000000000000000000000000000000006c47304402202306489afef52a6f62e90bf750bbcdf40c06f5c6b138286e6b6b86176bb9341802200dba98486ea68380f47ebb19a7df173b99e6bc9c681d6ccf3bde31465d1f16b3012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff010000000000000000015100000000", true], +"01000000020001000000000000000000000000000000000000000000000000000000000000000000006c47304402204bb1197053d0d7799bf1b30cd503c44b58d6240cccbdc85b6fe76d087980208f02204beeed78200178ffc6c74237bb74b3f276bbb4098b5605d814304fe128bf1431012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff0001000000000000000000000000000000000000000000000000000000000000000000006c47304402202306489afef52a6f62e90bf750bbcdf40c06f5c6b138286e6b6b86176bb9341802200dba98486ea68380f47ebb19a7df173b99e6bc9c681d6ccf3bde31465d1f16b3012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff010000000000000000015100000000", "P2SH"], ["Coinbase of size 1"], ["Note the input is just required to make the tester happy"], [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff010000000000000000015100000000", true], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff010000000000000000015100000000", "P2SH"], ["Coinbase of size 101"], ["Note the input is just required to make the tester happy"], [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"], + +["Null txin, but without being a coinbase (because there are two inputs)"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"], + ["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"01000000020000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff010000000000000000015100000000", "P2SH"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"], + ["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], +"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff010000000000000000015100000000", "P2SH"], + +["Same as the transactions in valid with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], + ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], + "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", "P2SH"], + +["CHECKMULTISIG with incorrect signature order"], +["Note the input is just required to make the tester happy"], +[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]], +"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe000048304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f401483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "P2SH"], + + +["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], +["It is an OP_CHECKMULTISIG with the dummy value missing"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004847304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], + + +["CHECKMULTISIG SCRIPT_VERIFY_NULLDUMMY tests:"], + +["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], +["It is an OP_CHECKMULTISIG with the dummy value set to something other than an empty string"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a010047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], + +["As above, but using a OP_1"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], + +["As above, but using a OP_1NEGATE"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], + +["As above, but with the dummy byte missing"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004847304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], + + +["Empty stack when we try to run CHECKSIG"], +[[["ad503f72c18df5801ee64d76090afe4c607fb2b822e9b7b63c5826c50e22fc3b", 0, "0x21 0x027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5 CHECKSIG NOT"]], +"01000000013bfc220ec526583cb6b7e922b8b27f604cfe0a09764de61e80f58dc1723f50ad0000000000ffffffff0101000000000000002321027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5ac00000000", "P2SH"], + + +["Inverted versions of tx_valid CODESEPARATOR IF block tests"], + +["CODESEPARATOR in an unexecuted IF block does not change what is hashed"], +[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]], +"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0151ffffffff010000000000000000016a00000000", "P2SH"], + +["As above, with the IF block executed"], +[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]], +"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510100ffffffff010000000000000000016a00000000", "P2SH"], + +["CHECKLOCKTIMEVERIFY tests"], + +["By-height locks, with argument just beyond tx nLockTime"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKLOCKTIMEVERIFY 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], + +["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 CHECKLOCKTIMEVERIFY 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Argument missing"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "CHECKLOCKTIMEVERIFY 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000001b1010000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Argument negative with by-blockheight nLockTime=0"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Argument negative with by-blocktime nLockTime=500,000,000"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b1010000000100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Input locked"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1ffffffff0100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"] , + ["0000000000000000000000000000000000000000000000000000000000000200", 1, "1"]], +"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Argument/tx height/time mismatch, both versions"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b100000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Argument 2^32 with nLockTime=2^32-1"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 CHECKLOCKTIMEVERIFY 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Same, but with nLockTime=2^31-1"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKLOCKTIMEVERIFY 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f", "P2SH,CHECKLOCKTIMEVERIFY"], + +["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 CHECKLOCKTIMEVERIFY 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Failure due to failing CHECKLOCKTIMEVERIFY in scriptSig"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Failure due to failing CHECKLOCKTIMEVERIFY in redeemScript"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["A transaction with a non-standard DER signature."], +[[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]], +"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH,DERSIG"], + +["CHECKSEQUENCEVERIFY tests"], + +["By-height locks, with argument just beyond txin.nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["By-time locks, with argument just beyond txin.nSequence (but within numerical boundries)"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument missing"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument negative with by-blockheight txin.nSequence=0"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument negative with by-blocktime txin.nSequence=CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument/tx height/time mismatch, both versions"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Failure due to failing CHECKSEQUENCEVERIFY in scriptSig"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Failure due to failing CHECKSEQUENCEVERIFY in redeemScript"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]], +"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Failure due to insufficient tx.nVersion (<2)"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -["Null txin"], -[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "HASH160 0x14 0x02dae7dbbda56097959cba59b1989dd3e47937bf EQUAL"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", true] +["Make diffs cleaner by leaving a comment here without comma at the end"] ] diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json index 5528ae72..24bde1ef 100644 --- a/src/test/data/tx_valid.json +++ b/src/test/data/tx_valid.json @@ -2,7 +2,7 @@ ["The following are deserialized transactions which are valid."], ["They are in the form"], ["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], -["serializedTransaction, enforceP2SH]"], +["serializedTransaction, verifyFlags]"], ["Objects that are only a single string (like this one) are ignored"], ["The following is 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], @@ -10,62 +10,312 @@ ["See http://r6.ca/blog/20111119T211504Z.html"], ["It is also the first OP_CHECKMULTISIG transaction in standard form"], [[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", true], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], ["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], -["It has an arbitrary extra byte stuffed into the signature at pos length - 2"], +["It is an OP_CHECKMULTISIG with an arbitrary extra byte stuffed into the signature at pos length - 2"], +["The dummy byte is fine however, so the NULLDUMMY flag should be happy"], [[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004A0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", true], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], + +["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], +["It is an OP_CHECKMULTISIG with the dummy value set to something other than an empty string"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], + +["As above, but using a OP_1"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], + +["As above, but using a OP_1NEGATE"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], ["The following is c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"], ["It is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)"], [[["406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602", 0, "DUP HASH160 0x14 0xdc44b1164188067c3a32d4780f5996fa14a4f2d9 EQUALVERIFY CHECKSIG"]], -"01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", true], +"01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", "P2SH"], ["A nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], ["Same as above, but with the signature duplicated in the scriptPubKey with the proper pushdata prefix"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], ["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"], ["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"], [[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"], ["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]], -"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", true], +"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "P2SH"], ["The following tests for the presence of a bug in the handling of SIGHASH_SINGLE"], ["It results in signing the constant 1, instead of something generated based on the transaction,"], ["when the input doing the signing has an index greater than the maximum output index"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"]], -"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", true], +"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"], ["An invalid P2SH Transaction"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], -"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", false], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "NONE"], ["A valid P2SH Transaction using the standard transaction type put forth in BIP 16"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", "P2SH"], -["Tests for CTransaction::CheckTransaction()"], +["Tests for CheckTransaction()"], ["MAX_MONEY output"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", "P2SH"], ["MAX_MONEY output + 0 output"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", true], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", "P2SH"], ["Coinbase of size 2"], ["Note the input is just required to make the tester happy"], [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", true], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", "P2SH"], ["Coinbase of size 100"], ["Note the input is just required to make the tester happy"], [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true] +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"], + +["Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], + ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], + "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"], + +["Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], + ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], + "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"], + +["afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae which has several SIGHASH_SINGLE signatures"], +[[["63cfa5a09dc540bf63e53713b82d9ea3692ca97cd608c384f2aa88e51a0aac70", 0, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"], + ["04e8d0fcf3846c6734477b98f0f3d4badfb78f020ee097a0be5fe347645b817d", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"], + ["ee1377aff5d0579909e11782e1d2f5f7b84d26537be7f5516dd4e43373091f3f", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"]], + "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000", "P2SH"], + + ["ddc454a1c0c35c188c98976b17670f69e586d9c0f3593ea879928332f0a069e7, which spends an input that pushes using a PUSHDATA1 that is negative when read as signed"], + [[["c5510a5dd97a25f43175af1fe649b707b1df8e1a41489bac33a23087027a2f48", 0, "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG"]], + "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000", "P2SH"], + +["Correct signature order"], +["Note the input is just required to make the tester happy"], +[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]], +"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "P2SH"], + +["cc60b1f899ec0a69b7c3f25ddf32c4524096a9c5b01cbd84c6d0312a0c478984, which is a fairly strange transaction which relies on OP_CHECKSIG returning 0 when checking a completely invalid sig of length 0"], +[[["cbebc4da731e8995fe97f6fadcd731b36ad40e5ecb31e38e904f6e5982fa09f7", 0, "0x2102085c6600657566acc2d6382a47bc3f324008d2aa10940dd7705a48aa2a5a5e33ac7c2103f5d0fb955f95dd6be6115ce85661db412ec6a08abcbfce7da0ba8297c6cc0ec4ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a5479827701200122a59a5379827701200122a59a6353798277537982778779679a68"]], +"0100000001f709fa82596e4f908ee331cb5e0ed46ab331d7dcfaf697fe95891e73dac4ebcb000000008c20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100a9df60536df5733dd0de6bc921fab0b3eee6426501b43a228afa2c90072eb5ca02201c78b74266fac7d1db5deff080d8a403743203f109fbcabf6d5a760bf87386d20100ffffffff01c075790000000000232103611f9a45c18f28f06f19076ad571c344c82ce8fcfe34464cf8085217a2d294a6ac00000000", "P2SH"], + +["Empty pubkey"], +[[["229257c295e7f555421c1bfec8538dd30a4b5c37c1c8810bbe83cafa7811652c", 0, "0x00 CHECKSIG NOT"]], +"01000000012c651178faca83be0b81c8c1375c4b0ad38d53c8fe1b1c4255f5e795c25792220000000049483045022100d6044562284ac76c985018fc4a90127847708c9edb280996c507b28babdc4b2a02203d74eca3f1a4d1eea7ff77b528fde6d5dc324ec2dbfdb964ba885f643b9704cd01ffffffff010100000000000000232102c2410f8891ae918cab4ffc4bb4a3b0881be67c7a1e7faa8b5acf9ab8932ec30cac00000000", "P2SH"], + +["Empty signature"], +[[["9ca93cfd8e3806b9d9e2ba1cf64e3cc6946ee0119670b1796a09928d14ea25f7", 0, "0x21 0x028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02 CHECKSIG NOT"]], +"0100000001f725ea148d92096a79b1709611e06e94c63c4ef61cbae2d9b906388efd3ca99c000000000100ffffffff0101000000000000002321028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac00000000", "P2SH"], + +[[["444e00ed7840d41f20ecd9c11d3f91982326c731a02f3c05748414a4fa9e59be", 0, "1 0x00 0x21 0x02136b04758b0b6e363e7a6fbe83aaf527a153db2b060d36cc29f7f8309ba6e458 2 CHECKMULTISIG"]], +"0100000001be599efaa4148474053c2fa031c7262398913f1dc1d9ec201fd44078ed004e44000000004900473044022022b29706cb2ed9ef0cb3c97b72677ca2dfd7b4160f7b4beb3ba806aa856c401502202d1e52582412eba2ed474f1f437a427640306fd3838725fab173ade7fe4eae4a01ffffffff010100000000000000232103ac4bba7e7ca3e873eea49e08132ad30c7f03640b6539e9b59903cf14fd016bbbac00000000", "P2SH"], + +[[["e16abbe80bf30c080f63830c8dbf669deaef08957446e95940227d8c5e6db612", 0, "1 0x21 0x03905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9f 0x00 2 CHECKMULTISIG"]], +"010000000112b66d5e8c7d224059e946749508efea9d66bf8d0c83630f080cf30be8bb6ae100000000490047304402206ffe3f14caf38ad5c1544428e99da76ffa5455675ec8d9780fac215ca17953520220779502985e194d84baa36b9bd40a0dbd981163fa191eb884ae83fc5bd1c86b1101ffffffff010100000000000000232103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9fac00000000", "P2SH"], + +[[["ebbcf4bfce13292bd791d6a65a2a858d59adbf737e387e40370d4e64cc70efb0", 0, "2 0x21 0x033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194 0x21 0x03a88b326f8767f4f192ce252afe33c94d25ab1d24f27f159b3cb3aa691ffe1423 2 CHECKMULTISIG NOT"]], +"0100000001b0ef70cc644e0d37407e387e73bfad598d852a5aa6d691d72b2913cebff4bceb000000004a00473044022068cd4851fc7f9a892ab910df7a24e616f293bcb5c5fbdfbc304a194b26b60fba022078e6da13d8cb881a22939b952c24f88b97afd06b4c47a47d7f804c9a352a6d6d0100ffffffff0101000000000000002321033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194ac00000000", "P2SH"], + +[[["ba4cd7ae2ad4d4d13ebfc8ab1d93a63e4a6563f25089a18bf0fc68f282aa88c1", 0, "2 0x21 0x037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1 0x21 0x02edc823cd634f2c4033d94f5755207cb6b60c4b1f1f056ad7471c47de5f2e4d50 2 CHECKMULTISIG NOT"]], +"0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba000000004b0000483045022100940378576e069aca261a6b26fb38344e4497ca6751bb10905c76bb689f4222b002204833806b014c26fd801727b792b1260003c55710f87c5adbd7a9cb57446dbc9801ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac00000000", "P2SH"], + + +["OP_CODESEPARATOR tests"], + +["Test that SignatureHash() removes OP_CODESEPARATOR with FindAndDelete()"], +[[["bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224", 0, "CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]], +"01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000004a493046022100a576b52051962c25e642c0fd3d77ee6c92487048e5d90818bcf5b51abaccd7900221008204f8fb121be4ec3b24483b1f92d89b1b0548513a134e345c5442e86e8617a501ffffffff010000000000000000016a00000000", "P2SH"], +[[["83e194f90b6ef21fa2e3a365b63794fb5daa844bdc9b25de30899fcfe7b01047", 0, "CODESEPARATOR CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]], +"01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000004a493046022100a166121a61b4eeb19d8f922b978ff6ab58ead8a5a5552bf9be73dc9c156873ea02210092ad9bc43ee647da4f6652c320800debcf08ec20a094a0aaf085f63ecb37a17201ffffffff010000000000000000016a00000000", "P2SH"], + +["Hashed data starts at the CODESEPARATOR"], +[[["326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CODESEPARATOR CHECKSIG"]], +"01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000004948304502203bf754d1c6732fbf87c5dcd81258aefd30f2060d7bd8ac4a5696f7927091dad1022100f5bcb726c4cf5ed0ed34cc13dadeedf628ae1045b7cb34421bc60b89f4cecae701ffffffff010000000000000000016a00000000", "P2SH"], + +["But only if execution has reached it"], +[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 1"]], +"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000924830450221009c0a27f886a1d8cb87f6f595fbc3163d28f7a81ec3c4b252ee7f3ac77fd13ffa02203caa8dfa09713c8c4d7ef575c75ed97812072405d932bd11e6a1593a98b679370148304502201e3861ef39a526406bad1e20ecad06be7375ad40ddb582c9be42d26c3a0d7b240221009d0a3985e96522e59635d19cc4448547477396ce0ef17a58e7d74c3ef464292301ffffffff010000000000000000016a00000000", "P2SH"], + +["CODESEPARATOR in an unexecuted IF block does not change what is hashed"], +[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]], +"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0100ffffffff010000000000000000016a00000000", "P2SH"], + +["As above, with the IF block executed"], +[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]], +"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510151ffffffff010000000000000000016a00000000", "P2SH"], + + +["CHECKSIG is legal in scriptSigs"], +[[["ccf7f4053a02e653c36ac75c891b7496d0dc5ce5214f6c913d9cf8f1329ebee0", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]], +"0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc00000000d86149304602210086e5f736a2c3622ebb62bd9d93d8e5d76508b98be922b97160edc3dcca6d8c47022100b23c312ac232a4473f19d2aeb95ab7bdf2b65518911a0d72d50e38b5dd31dc820121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac4730440220508fa761865c8abd81244a168392876ee1d94e8ed83897066b5e2df2400dad24022043f5ee7538e87e9c6aef7ef55133d3e51da7cc522830a9c4d736977a76ef755c0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"], + +["Same semantics for OP_CODESEPARATOR"], +[[["10c9f0effe83e97f80f067de2b11c6a00c3088a4bce42c5ae761519af9306f3c", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]], +"01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c91001000000e608646561646265656675ab61493046022100ce18d384221a731c993939015e3d1bcebafb16e8c0b5b5d14097ec8177ae6f28022100bcab227af90bab33c3fe0a9abfee03ba976ee25dc6ce542526e9b2e56e14b7f10121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac493046022100c3b93edcc0fd6250eb32f2dd8a0bba1754b0f6c3be8ed4100ed582f3db73eba2022100bf75b5bd2eff4d6bf2bda2e34a40fcc07d4aa3cf862ceaa77b47b81eff829f9a01ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"], + +["Signatures are removed from the script they are in by FindAndDelete() in the CHECKSIG code; even multiple instances of one signature can be removed."], +[[["6056ebd549003b10cbbd915cea0d82209fe40b8617104be917a26fa92cbe3d6f", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]], +"01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb566000000000fd1d0147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac47304402203757e937ba807e4a5da8534c17f9d121176056406a6465054bdd260457515c1a02200f02eccf1bec0f3a0d65df37889143c2e88ab7acec61a7b6f5aa264139141a2b0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"], + +["That also includes ahead of the opcode being executed."], +[[["5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]], +"01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"], + +["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."], + +["Here's an example on mainnet within a P2SH redeemScript. Remarkably it's a standard transaction in <0.9"], +[[["b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"], + ["ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742", 0, "HASH160 0x14 0xd8dacdadb7462ae15cd906f1878706d0da8660e6 EQUAL"]], +"0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd260100483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000", "P2SH"], + +["Same idea, but with bare CHECKMULTISIG"], +[[["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"], + ["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 1, "2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG"]], +"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"], + + +["CHECKLOCKTIMEVERIFY tests"], + +["By-height locks, with argument == 0 and == tx nLockTime"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], + +["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Any non-maxint nSequence is fine"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["The argument can be calculated rather than created directly by a PUSHDATA"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD CHECKLOCKTIMEVERIFY 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Perhaps even by an ADD producing a 5-byte result that is out of bounds for other opcodes"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD CHECKLOCKTIMEVERIFY 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"], + +["5 byte non-minimally-encoded arguments are valid"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 CHECKLOCKTIMEVERIFY 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Valid CHECKLOCKTIMEVERIFY in scriptSig"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Valid CHECKLOCKTIMEVERIFY in redeemScript"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["A transaction with a non-standard DER signature."], +[[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]], +"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH"], + +["CHECKSEQUENCEVERIFY tests"], + +["By-height locks, with argument == 0 and == txin.nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["By-time locks, with argument == 0 and == txin.nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Upper sequence with upper sequence is fine"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument 2^31 with various nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument 2^32-1 with various nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument 3<<31 with various nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["5 byte non-minimally-encoded operandss are valid"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["The argument can be calculated rather than created directly by a PUSHDATA"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194303 1ADD CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 1SUB CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["An ADD producing a 5-byte result that sets CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 65536 CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 4259840 ADD CHECKSEQUENCEVERIFY 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Valid CHECKSEQUENCEVERIFY in scriptSig"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Valid CHECKSEQUENCEVERIFY in redeemScript"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]], +"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Make diffs cleaner by leaving a comment here without comma at the end"] ] diff --git a/src/test/data/txcreate1.hex b/src/test/data/txcreate1.hex new file mode 100644 index 00000000..e2981a51 --- /dev/null +++ b/src/test/data/txcreate1.hex @@ -0,0 +1 @@ +01000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fffffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d717000000001976a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac00000000 diff --git a/src/test/data/txcreate2.hex b/src/test/data/txcreate2.hex new file mode 100644 index 00000000..5243c2d0 --- /dev/null +++ b/src/test/data/txcreate2.hex @@ -0,0 +1 @@ +01000000000100000000000000000000000000 diff --git a/src/test/data/txcreatedata1.hex b/src/test/data/txcreatedata1.hex new file mode 100644 index 00000000..eccc7604 --- /dev/null +++ b/src/test/data/txcreatedata1.hex @@ -0,0 +1 @@ +01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d71700000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000 diff --git a/src/test/data/txcreatedata2.hex b/src/test/data/txcreatedata2.hex new file mode 100644 index 00000000..3c7644c2 --- /dev/null +++ b/src/test/data/txcreatedata2.hex @@ -0,0 +1 @@ +01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0000000000000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000 diff --git a/src/test/data/txcreatesign.hex b/src/test/data/txcreatesign.hex new file mode 100644 index 00000000..a46fcc88 --- /dev/null +++ b/src/test/data/txcreatesign.hex @@ -0,0 +1 @@ +01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008b48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000 diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp new file mode 100644 index 00000000..bb818d2a --- /dev/null +++ b/src/test/dbwrapper_tests.cpp @@ -0,0 +1,347 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "dbwrapper.h" +#include "random.h" +#include "test/test_bitcoin.h" +#include "uint256.h" + +#include +#include // for 'operator+=()' +#include + +using namespace std; +using namespace boost::assign; // bring 'operator+=()' into scope +using namespace boost::filesystem; + +// Test if a string consists entirely of null characters +bool is_null_key(const vector &key) +{ + bool isnull = true; + + for (unsigned int i = 0; i < key.size(); i++) + isnull &= (key[i] == '\x00'); + + return isnull; +} + +BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(dbwrapper) +{ + // Perform tests both obfuscated and non-obfuscated. + for (int i = 0; i < 2; i++) + { + bool obfuscate = (bool)i; + fs::path ph = fs::temp_directory_path() / fs::unique_path(); + CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); + char key = 'k'; + uint256 in = GetRandHash(); + uint256 res; + + // Ensure that we're doing real obfuscation when obfuscate=true + BOOST_CHECK(obfuscate != is_null_key(dbwrapper_private::GetObfuscateKey(dbw))); + + BOOST_CHECK(dbw.Write(key, in)); + BOOST_CHECK(dbw.Read(key, res)); + BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); + } +} + +// Test batch operations +BOOST_AUTO_TEST_CASE(dbwrapper_batch) +{ + // Perform tests both obfuscated and non-obfuscated. + for (int i = 0; i < 2; i++) + { + bool obfuscate = (bool)i; + fs::path ph = fs::temp_directory_path() / fs::unique_path(); + CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); + + char key = 'i'; + uint256 in = GetRandHash(); + char key2 = 'j'; + uint256 in2 = GetRandHash(); + char key3 = 'k'; + uint256 in3 = GetRandHash(); + + uint256 res; + CDBBatch batch(dbw); + + batch.Write(key, in); + batch.Write(key2, in2); + batch.Write(key3, in3); + + // Remove key3 before it's even been written + batch.Erase(key3); + + dbw.WriteBatch(batch); + + BOOST_CHECK(dbw.Read(key, res)); + BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); + BOOST_CHECK(dbw.Read(key2, res)); + BOOST_CHECK_EQUAL(res.ToString(), in2.ToString()); + + // key3 never should've been written + BOOST_CHECK(dbw.Read(key3, res) == false); + } +} + +BOOST_AUTO_TEST_CASE(dbwrapper_iterator) +{ + // Perform tests both obfuscated and non-obfuscated. + for (int i = 0; i < 2; i++) + { + bool obfuscate = (bool)i; + fs::path ph = fs::temp_directory_path() / fs::unique_path(); + CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); + + // The two keys are intentionally chosen for ordering + char key = 'j'; + uint256 in = GetRandHash(); + BOOST_CHECK(dbw.Write(key, in)); + char key2 = 'k'; + uint256 in2 = GetRandHash(); + BOOST_CHECK(dbw.Write(key2, in2)); + + boost::scoped_ptr it(const_cast(&dbw)->NewIterator()); + + // Be sure to seek past the obfuscation key (if it exists) + it->Seek(key); + + char key_res; + uint256 val_res; + + it->GetKey(key_res); + it->GetValue(val_res); + BOOST_CHECK_EQUAL(key_res, key); + BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString()); + + it->Next(); + + it->GetKey(key_res); + it->GetValue(val_res); + BOOST_CHECK_EQUAL(key_res, key2); + BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString()); + + it->Next(); + BOOST_CHECK_EQUAL(it->Valid(), false); + } +} + +// Test that we do not obfuscation if there is existing data. +BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) +{ + // We're going to share this fs::path between two wrappers + fs::path ph = fs::temp_directory_path() / fs::unique_path(); + create_directories(ph); + + // Set up a non-obfuscated wrapper to write some initial data. + CDBWrapper *dbw = new CDBWrapper(ph, (1 << 10), false, false, false); + char key = 'k'; + uint256 in = GetRandHash(); + uint256 res; + + BOOST_CHECK(dbw->Write(key, in)); + BOOST_CHECK(dbw->Read(key, res)); + BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); + + // Call the destructor to free leveldb LOCK + delete dbw; + + // Now, set up another wrapper that wants to obfuscate the same directory + CDBWrapper odbw(ph, (1 << 10), false, false, true); + + // Check that the key/val we wrote with unobfuscated wrapper exists and + // is readable. + uint256 res2; + BOOST_CHECK(odbw.Read(key, res2)); + BOOST_CHECK_EQUAL(res2.ToString(), in.ToString()); + + BOOST_CHECK(!odbw.IsEmpty()); // There should be existing data + BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); // The key should be an empty string + + uint256 in2 = GetRandHash(); + uint256 res3; + + // Check that we can write successfully + BOOST_CHECK(odbw.Write(key, in2)); + BOOST_CHECK(odbw.Read(key, res3)); + BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString()); +} + +// Ensure that we start obfuscating during a reindex. +BOOST_AUTO_TEST_CASE(existing_data_reindex) +{ + // We're going to share this fs::path between two wrappers + fs::path ph = fs::temp_directory_path() / fs::unique_path(); + create_directories(ph); + + // Set up a non-obfuscated wrapper to write some initial data. + CDBWrapper *dbw = new CDBWrapper(ph, (1 << 10), false, false, false); + char key = 'k'; + uint256 in = GetRandHash(); + uint256 res; + + BOOST_CHECK(dbw->Write(key, in)); + BOOST_CHECK(dbw->Read(key, res)); + BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); + + // Call the destructor to free leveldb LOCK + delete dbw; + + // Simulate a -reindex by wiping the existing data store + CDBWrapper odbw(ph, (1 << 10), false, true, true); + + // Check that the key/val we wrote with unobfuscated wrapper doesn't exist + uint256 res2; + BOOST_CHECK(!odbw.Read(key, res2)); + BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); + + uint256 in2 = GetRandHash(); + uint256 res3; + + // Check that we can write successfully + BOOST_CHECK(odbw.Write(key, in2)); + BOOST_CHECK(odbw.Read(key, res3)); + BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString()); +} + +BOOST_AUTO_TEST_CASE(iterator_ordering) +{ + fs::path ph = fs::temp_directory_path() / fs::unique_path(); + CDBWrapper dbw(ph, (1 << 20), true, false, false); + for (int x = 0x00; x < 256; ++x) + { + uint8_t key = x; + uint32_t value = x * x; + BOOST_CHECK(dbw.Write(key, value)); + } + + boost::scoped_ptr it(const_cast(&dbw)->NewIterator()); + for (int c = 0; c < 2; ++c) + { + int seek_start; + if (c == 0) + seek_start = 0x00; + else + seek_start = 0x80; + it->Seek((uint8_t)seek_start); + for (int x = seek_start; x < 256; ++x) + { + uint8_t key; + uint32_t value; + BOOST_CHECK(it->Valid()); + if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure + break; + BOOST_CHECK(it->GetKey(key)); + BOOST_CHECK(it->GetValue(value)); + BOOST_CHECK_EQUAL(key, x); + BOOST_CHECK_EQUAL(value, x * x); + it->Next(); + } + BOOST_CHECK(!it->Valid()); + } +} + +struct StringContentsSerializer +{ + // Used to make two serialized objects the same while letting them have a different lengths + // This is a terrible idea + string str; + StringContentsSerializer() {} + StringContentsSerializer(const string &inp) : str(inp) {} + StringContentsSerializer &operator+=(const string &s) + { + str += s; + return *this; + } + StringContentsSerializer &operator+=(const StringContentsSerializer &s) { return *this += s.str; } + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream &s, Operation ser_action) + { + if (ser_action.ForRead()) + { + str.clear(); + char c = 0; + while (true) + { + try + { + READWRITE(c); + str.push_back(c); + } + catch (const std::ios_base::failure &e) + { + break; + } + } + } + else + { + for (size_t i = 0; i < str.size(); i++) + READWRITE(str[i]); + } + } +}; + +BOOST_AUTO_TEST_CASE(iterator_string_ordering) +{ + char buf[10]; + + fs::path ph = fs::temp_directory_path() / fs::unique_path(); + CDBWrapper dbw(ph, (1 << 20), true, false, false); + for (int x = 0x00; x < 10; ++x) + { + for (int y = 0; y < 10; y++) + { + sprintf(buf, "%d", x); + StringContentsSerializer key(buf); + for (int z = 0; z < y; z++) + key += key; + uint32_t value = x * x; + BOOST_CHECK(dbw.Write(key, value)); + } + } + + boost::scoped_ptr it(const_cast(&dbw)->NewIterator()); + for (int c = 0; c < 2; ++c) + { + int seek_start; + if (c == 0) + seek_start = 0; + else + seek_start = 5; + sprintf(buf, "%d", seek_start); + StringContentsSerializer seek_key(buf); + it->Seek(seek_key); + for (int x = seek_start; x < 10; ++x) + { + for (int y = 0; y < 10; y++) + { + sprintf(buf, "%d", x); + string exp_key(buf); + for (int z = 0; z < y; z++) + exp_key += exp_key; + StringContentsSerializer key; + uint32_t value; + BOOST_CHECK(it->Valid()); + if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure + break; + BOOST_CHECK(it->GetKey(key)); + BOOST_CHECK(it->GetValue(value)); + BOOST_CHECK_EQUAL(key.str, exp_key); + BOOST_CHECK_EQUAL(value, x * x); + it->Next(); + } + } + BOOST_CHECK(!it->Valid()); + } +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/excessiveblock_test.cpp b/src/test/excessiveblock_test.cpp new file mode 100644 index 00000000..4f7ac2a5 --- /dev/null +++ b/src/test/excessiveblock_test.cpp @@ -0,0 +1,283 @@ +#include "unlimited.h" + +#include "../consensus/consensus.h" +#include "test/test_bitcoin.h" + +#include +#include +#include + +using namespace std; + +// Defined in rpc_tests.cpp not bitcoin-cli.cpp +extern UniValue CallRPC(string strMethod); + +BOOST_FIXTURE_TEST_SUITE(excessiveblock_test, TestingSetup) + +BOOST_AUTO_TEST_CASE(rpc_excessive) +{ + BOOST_CHECK_NO_THROW(CallRPC("getexcessiveblock")); + + BOOST_CHECK_NO_THROW(CallRPC("getminingmaxblock")); + + BOOST_CHECK_THROW(CallRPC("setexcessiveblock not_uint"), runtime_error); + BOOST_CHECK_THROW(CallRPC("setexcessiveblock 4000000 not_uint"), boost::bad_lexical_cast); + BOOST_CHECK_THROW(CallRPC("setexcessiveblock 4000000 -1"), boost::bad_lexical_cast); + BOOST_CHECK_THROW(CallRPC("setexcessiveblock -1 0"), boost::bad_lexical_cast); + + BOOST_CHECK_THROW(CallRPC("setexcessiveblock 1000 1"), runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("setminingmaxblock 1000")); + BOOST_CHECK_NO_THROW(CallRPC("setexcessiveblock 1000 1")); + + BOOST_CHECK_THROW(CallRPC("setexcessiveblock 1000 0 0"), runtime_error); + + BOOST_CHECK_THROW(CallRPC("setminingmaxblock"), runtime_error); + BOOST_CHECK_THROW(CallRPC("setminingmaxblock 100000"), runtime_error); + BOOST_CHECK_THROW(CallRPC("setminingmaxblock not_uint"), boost::bad_lexical_cast); + BOOST_CHECK_THROW(CallRPC("setminingmaxblock -1"), boost::bad_lexical_cast); + BOOST_CHECK_THROW(CallRPC("setminingmaxblock 0"), runtime_error); + BOOST_CHECK_THROW(CallRPC("setminingmaxblock 0 0"), runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("setminingmaxblock 1000")); + BOOST_CHECK_NO_THROW(CallRPC("setminingmaxblock 101")); + + // Set it back to the expected values for other tests + BOOST_CHECK_NO_THROW(CallRPC("setexcessiveblock 16000000 12")); + BOOST_CHECK_NO_THROW(CallRPC("setminingmaxblock 1000000")); +} + +BOOST_AUTO_TEST_CASE(buip005) +{ + string exceptedEB; + string exceptedAD; + excessiveBlockSize = 1000000; + excessiveAcceptDepth = 9999999; + exceptedEB = "EB1"; + exceptedAD = "AD9999999"; + settingsToUserAgentString(); + BOOST_CHECK_MESSAGE(BUComments.front() == exceptedEB, + "EB ought to have been " << exceptedEB << " when excessiveBlockSize = " << excessiveBlockSize << " but was " + << BUComments.front()); + BOOST_CHECK_MESSAGE(BUComments.back() == exceptedAD, + "AD ought to have been " << exceptedAD << " when excessiveBlockSize = " << excessiveAcceptDepth); + excessiveBlockSize = 100000; + excessiveAcceptDepth = 9999999 + 1; + exceptedEB = "EB0.1"; + exceptedAD = "AD9999999"; + settingsToUserAgentString(); + BOOST_CHECK_MESSAGE(BUComments.front() == exceptedEB, + "EB ought to have been " << exceptedEB << " when excessiveBlockSize = " << excessiveBlockSize << " but was " + << BUComments.front()); + BOOST_CHECK_MESSAGE(BUComments.back() == exceptedAD, + "AD ought to have been " << exceptedAD << " when excessiveBlockSize = " << excessiveAcceptDepth); + excessiveBlockSize = 10000; + exceptedEB = "EB0"; + settingsToUserAgentString(); + BOOST_CHECK_MESSAGE(BUComments.front() == exceptedEB, + "EB ought to have been " << exceptedEB << " when excessiveBlockSize = " << excessiveBlockSize << " but was " + << BUComments.front()); + excessiveBlockSize = 1670000; + exceptedEB = "EB1.6"; + settingsToUserAgentString(); + BOOST_CHECK_MESSAGE(BUComments.front() == exceptedEB, + "EB ought to have been rounded to " << exceptedEB << " when excessiveBlockSize = " << excessiveBlockSize + << " but was " << BUComments.front()); + excessiveBlockSize = 150000; + exceptedEB = "EB0.1"; + settingsToUserAgentString(); + BOOST_CHECK_MESSAGE(BUComments.front() == exceptedEB, + "EB ought to have been rounded to " << exceptedEB << " when excessiveBlockSize = " << excessiveBlockSize + << " but was " << BUComments.front()); + excessiveBlockSize = 0; + exceptedEB = "EB0"; + settingsToUserAgentString(); + BOOST_CHECK_MESSAGE(BUComments.front() == exceptedEB, + "EB ought to have been rounded to " << exceptedEB << " when excessiveBlockSize = " << excessiveBlockSize + << " but was " << BUComments.front()); + excessiveBlockSize = 3800000000; + exceptedEB = "EB3800"; + settingsToUserAgentString(); + BOOST_CHECK_MESSAGE(BUComments.front() == exceptedEB, + "EB ought to have been rounded to " << exceptedEB << " when excessiveBlockSize = " << excessiveBlockSize + << " but was " << BUComments.front()); + excessiveBlockSize = 49200000000; + exceptedEB = "EB49200"; + settingsToUserAgentString(); + BOOST_CHECK_MESSAGE(BUComments.front() == exceptedEB, + "EB ought to have been rounded to " << exceptedEB << " when excessiveBlockSize = " << excessiveBlockSize + << " but was " << BUComments.front()); + // set back to defaults + excessiveBlockSize = 1000000; + excessiveAcceptDepth = 4; +} + + +BOOST_AUTO_TEST_CASE(excessiveChecks) +{ + CBlock block; + + excessiveBlockSize = 16000000; // Ignore excessive block size when checking sigops and block effort + + // Check sigops values + + // Maintain compatibility with the old sigops calculator for blocks <= 1MB + BOOST_CHECK_MESSAGE(false == CheckExcessive(block, BLOCKSTREAM_CORE_MAX_BLOCK_SIZE - 1, + BLOCKSTREAM_CORE_MAX_BLOCK_SIGOPS, 100, 100), + "improper sigops"); + BOOST_CHECK_MESSAGE(false == CheckExcessive(block, BLOCKSTREAM_CORE_MAX_BLOCK_SIZE - 1, + BLOCKSTREAM_CORE_MAX_BLOCK_SIGOPS, 100, 100), + "improper sigops"); + BOOST_CHECK_MESSAGE( + false == CheckExcessive(block, BLOCKSTREAM_CORE_MAX_BLOCK_SIZE, BLOCKSTREAM_CORE_MAX_BLOCK_SIGOPS, 100, 100), + "improper sigops"); + + BOOST_CHECK_MESSAGE(true == CheckExcessive(block, BLOCKSTREAM_CORE_MAX_BLOCK_SIZE - 1, + BLOCKSTREAM_CORE_MAX_BLOCK_SIGOPS + 1, 100, 100), + "improper sigops"); + BOOST_CHECK_MESSAGE( + true == CheckExcessive(block, BLOCKSTREAM_CORE_MAX_BLOCK_SIZE, BLOCKSTREAM_CORE_MAX_BLOCK_SIGOPS + 1, 100, 100), + "improper sigops"); + + + // Check sigops > 1MB. + BOOST_CHECK_MESSAGE( + false == CheckExcessive(block, 1000000 + 1, (blockSigopsPerMb.value * 2), 100, 100), "improper sigops"); + BOOST_CHECK_MESSAGE( + true == CheckExcessive(block, 1000000 + 1, (blockSigopsPerMb.value * 2) + 1, 100, 100), "improper sigops"); + BOOST_CHECK_MESSAGE( + true == CheckExcessive(block, (2 * 1000000), (blockSigopsPerMb.value * 2) + 1, 100, 100), "improper sigops"); + BOOST_CHECK_MESSAGE(false == CheckExcessive(block, (2 * 1000000) + 1, (blockSigopsPerMb.value * 2) + 1, 100, 100), + "improper sigops"); + + + // Check tx size values + maxTxSize.value = DEFAULT_LARGEST_TRANSACTION; + + // Within a 1 MB block, a 1MB transaction is not excessive + BOOST_CHECK_MESSAGE( + false == CheckExcessive(block, BLOCKSTREAM_CORE_MAX_BLOCK_SIZE, 1, 1, BLOCKSTREAM_CORE_MAX_BLOCK_SIZE), + "improper max tx"); + + // With a > 1 MB block, use the maxTxSize to determine + BOOST_CHECK_MESSAGE( + false == CheckExcessive(block, BLOCKSTREAM_CORE_MAX_BLOCK_SIZE + 1, 1, 1, maxTxSize.value), "improper max tx"); + BOOST_CHECK_MESSAGE(true == CheckExcessive(block, BLOCKSTREAM_CORE_MAX_BLOCK_SIZE + 1, 1, 1, maxTxSize.value + 1), + "improper max tx"); +} + +BOOST_AUTO_TEST_CASE(check_validator_rule) +{ + BOOST_CHECK(MiningAndExcessiveBlockValidatorRule(1000000, 1000000)); + BOOST_CHECK(MiningAndExcessiveBlockValidatorRule(16000000, 1000000)); + BOOST_CHECK(MiningAndExcessiveBlockValidatorRule(1000001, 1000000)); + + BOOST_CHECK(!MiningAndExcessiveBlockValidatorRule(1000000, 1000001)); + BOOST_CHECK(!MiningAndExcessiveBlockValidatorRule(1000000, 16000000)); + + BOOST_CHECK(MiningAndExcessiveBlockValidatorRule(1357, 1357)); + BOOST_CHECK(MiningAndExcessiveBlockValidatorRule(161616, 2222)); + BOOST_CHECK(MiningAndExcessiveBlockValidatorRule(88889, 88888)); + + BOOST_CHECK(!MiningAndExcessiveBlockValidatorRule(929292, 929293)); + BOOST_CHECK(!MiningAndExcessiveBlockValidatorRule(4, 234245)); +} + +BOOST_AUTO_TEST_CASE(check_excessive_validator) +{ + uint64_t c_mgb = maxGeneratedBlock; + uint64_t c_ebs = excessiveBlockSize; + + // fudge global variables.... + maxGeneratedBlock = 1000000; + excessiveBlockSize = 888; + + unsigned int tmpExcessive = 1000000; + std::string str; + + str = ExcessiveBlockValidator(tmpExcessive, NULL, true); + BOOST_CHECK(str.empty()); + + excessiveBlockSize = 888; + str = ExcessiveBlockValidator(tmpExcessive, NULL, false); + BOOST_CHECK(str.empty()); + + str = ExcessiveBlockValidator(tmpExcessive, (uint64_t *)42, true); + BOOST_CHECK(str.empty()); + + tmpExcessive = maxGeneratedBlock + 1; + + str = ExcessiveBlockValidator(tmpExcessive, NULL, true); + BOOST_CHECK(str.empty()); + + excessiveBlockSize = 888; + str = ExcessiveBlockValidator(tmpExcessive, NULL, false); + BOOST_CHECK(str.empty()); + + str = ExcessiveBlockValidator(tmpExcessive, (uint64_t *)42, true); + BOOST_CHECK(str.empty()); + + tmpExcessive = maxGeneratedBlock - 1; + + str = ExcessiveBlockValidator(tmpExcessive, NULL, true); + BOOST_CHECK(!str.empty()); + + str = ExcessiveBlockValidator(tmpExcessive, NULL, false); + BOOST_CHECK(str.empty()); + + str = ExcessiveBlockValidator(tmpExcessive, (uint64_t *)42, true); + BOOST_CHECK(!str.empty()); + + maxGeneratedBlock = c_mgb; + excessiveBlockSize = c_ebs; +} + +BOOST_AUTO_TEST_CASE(check_generated_block_validator) +{ + uint64_t c_mgb = maxGeneratedBlock; + uint64_t c_ebs = excessiveBlockSize; + + // fudge global variables.... + maxGeneratedBlock = 888; + excessiveBlockSize = 1000000; + + uint64_t tmpMGB = 1000000; + std::string str; + + str = MiningBlockSizeValidator(tmpMGB, NULL, true); + BOOST_CHECK(str.empty()); + + maxGeneratedBlock = 8888881; + str = MiningBlockSizeValidator(tmpMGB, NULL, false); + BOOST_CHECK(str.empty()); + + str = MiningBlockSizeValidator(tmpMGB, (uint64_t *)42, true); + BOOST_CHECK(str.empty()); + + tmpMGB = excessiveBlockSize - 1; + + str = MiningBlockSizeValidator(tmpMGB, NULL, true); + BOOST_CHECK(str.empty()); + + maxGeneratedBlock = 8888881; + str = MiningBlockSizeValidator(tmpMGB, NULL, false); + BOOST_CHECK(str.empty()); + + str = MiningBlockSizeValidator(tmpMGB, (uint64_t *)42, true); + BOOST_CHECK(str.empty()); + + tmpMGB = excessiveBlockSize + 1; + + str = MiningBlockSizeValidator(tmpMGB, NULL, true); + BOOST_CHECK(!str.empty()); + + str = MiningBlockSizeValidator(tmpMGB, NULL, false); + BOOST_CHECK(str.empty()); + + str = MiningBlockSizeValidator(tmpMGB, (uint64_t *)42, true); + BOOST_CHECK(!str.empty()); + + maxGeneratedBlock = c_mgb; + excessiveBlockSize = c_ebs; +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/exploit_tests.cpp b/src/test/exploit_tests.cpp new file mode 100644 index 00000000..df76b1d5 --- /dev/null +++ b/src/test/exploit_tests.cpp @@ -0,0 +1,1083 @@ +// Copyright (c) 2016 Bitcoin Unlimited Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bloom.h" +#include "chainparams.h" +#include "dosman.h" +#include "main.h" +#include "net.h" +#include "primitives/block.h" +#include "protocol.h" +#include "random.h" +#include "requestManager.h" +#include "serialize.h" +#include "streams.h" +#include "streams.h" +#include "thinblock.h" +#include "txmempool.h" +#include "uint256.h" +#include "unlimited.h" +#include "util.h" +#include "utilstrencodings.h" +#include "version.h" + +#include "test/test_bitcoin.h" + +#include +#include +#include +#include + + +/** + * Generally this series of tests will do Message Consistency checking for p2p messages. If the messages are not + * formatted correctly then a ban will result. + * + * However we will also do other types of exploit testing, as much as is possible, through the unit test framework. + */ + +// NOTE: When creating test cases be sure to always set your nVersion and fSuccessfullyConneted flag as follows. +// +// CNode dummyNode1(INVALID_SOCKET, addr1, "", true); +// dummyNode1.nVersion = MIN_PEER_PROTO_VERSION; +// dummyNode1.fSuccessfullyConnected = true; + +extern std::atomic fIsInitialBlockDownload; + +CBlock TestBlock1() // Thanks dagurval :) +{ + // Block taken from bloom_tests.cpp merkle_block_1 + // Random real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af) + // With 9 txes + CDataStream stream( + ParseHex( + "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c" + "3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000" + "000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc" + "8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00" + "000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab2" + "4889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c31" + "1b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac00" + "0000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268" + "ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc" + "597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e5" + "71fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a" + "0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac00000000010000" + "0002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e" + "5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe6" + "7512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf97584" + "5c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035d" + "defb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14" + "a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14c" + "a4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043" + "410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9" + "d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5" + "c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e" + "5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d7" + "89904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c0000000000" + "1976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb" + "042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a" + "4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987da" + "d92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3" + "cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a91455056148" + "59643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00" + "000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc" + "2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f" + "7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c6" + "9b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa" + "4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702" + "200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f" + "388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acf" + "cab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48" + "cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805" + "c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1" + "d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd20000" + "00008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae" + "2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07" + "d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc65" + "14edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558" + "165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3" + "a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8eb" + "bb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166" + "d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229ce" + "fc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b6" + "3f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a3316" + "1dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688" + "ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a905" + "9cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c35306" + "9e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c" + "79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce30" + "12e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c0000" + "0000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"), + SER_NETWORK, PROTOCOL_VERSION); + CBlock block; + stream >> block; + return block; +}; +CBlock block = TestBlock1(); + + +CService ipaddress(uint32_t i, uint32_t port) +{ + struct in_addr s; + s.s_addr = i; + return CService(CNetAddr(s), port); +} + +// create dummy test addrs +CAddress addr1(ipaddress(0xa0b0c001, 10000)); +CAddress addr2(ipaddress(0xa0b0c002, 10001)); +CAddress addr3(ipaddress(0xa0b0c003, 10002)); +CAddress addr4(ipaddress(0xa0b0c004, 10003)); +CAddress addr5(ipaddress(0xa0b0c005, 10004)); + +// create recv queues +CDataStream vRecv1(SER_NETWORK, PROTOCOL_VERSION); +CDataStream vRecv2(SER_NETWORK, PROTOCOL_VERSION); +CDataStream vRecv3(SER_NETWORK, PROTOCOL_VERSION); +CDataStream vRecv4(SER_NETWORK, PROTOCOL_VERSION); +CDataStream vRecv5(SER_NETWORK, PROTOCOL_VERSION); + +// create a basic nullhash +uint256 nullhash; + + +BOOST_FIXTURE_TEST_SUITE(exploit_tests, TestingSetup) + +BOOST_AUTO_TEST_CASE(version_tests) +{ + int64_t nTime = GetTime(); + CAddress addrMe = GetLocalAddress(&addr1); + uint64_t nServices = 1; + + // Recieve VERSION with no prior VERSION received yet. Should not ban + vRecv1.clear(); + dosMan.ClearBanned(); + CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + dummyNode1.nVersion = 0; + dummyNode1.fSuccessfullyConnected = false; + int nVersion = MIN_PEER_PROTO_VERSION; + vRecv1 << nVersion << nServices << nTime << addrMe; + ProcessMessage(&dummyNode1, NetMsgType::VERSION, vRecv1, GetTime()); + SendMessages(&dummyNode1); + BOOST_CHECK(dummyNode1.nVersion); + BOOST_CHECK(!dosMan.IsBanned(addr1)); + + // Receive VERSION with no prior VERSION received but invalid protocol version, which should result in ban + vRecv1.clear(); + dosMan.ClearBanned(); + CNode dummyNode1a(INVALID_SOCKET, addr1, "", true); + dummyNode1a.nVersion = 0; + dummyNode1a.fSuccessfullyConnected = false; + nVersion = MIN_PEER_PROTO_VERSION - 1; + vRecv1 << nVersion << nServices << nTime << addrMe; + ProcessMessage(&dummyNode1a, NetMsgType::VERSION, vRecv1, GetTime()); + SendMessages(&dummyNode1a); + BOOST_CHECK(dummyNode1a.nVersion); + BOOST_CHECK(dosMan.IsBanned(addr1)); + + // Receive duplicate VERSION, nVersion will not be zero and should result in a disconnect + vRecv1.clear(); + dosMan.ClearBanned(); + CNode dummyNode2(INVALID_SOCKET, addr2, "", true); + dummyNode2.nVersion = MIN_PEER_PROTO_VERSION; + vRecv1 << nVersion << nServices << nTime << addrMe; + ProcessMessage(&dummyNode2, NetMsgType::VERSION, vRecv1, GetTime()); + SendMessages(&dummyNode2); + BOOST_CHECK(dummyNode2.nVersion); + BOOST_CHECK(dummyNode2.fDisconnect); + + // Receive any message without receiving the version message first - this should cause a disconnect + vRecv1.clear(); + dosMan.ClearBanned(); + CNode dummyNode3(INVALID_SOCKET, addr3, "", true); + dummyNode3.nVersion = 0; + ProcessMessage(&dummyNode3, NetMsgType::PING, vRecv1, GetTime()); + SendMessages(&dummyNode3); + BOOST_CHECK(!dummyNode3.nVersion); + BOOST_CHECK(dummyNode3.fDisconnect); +} + +BOOST_AUTO_TEST_CASE(verack_tests) +{ + // Receive VERACK after VERSION sent + vRecv1.clear(); + dosMan.ClearBanned(); + CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + dummyNode1.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode1.fSuccessfullyConnected = false; + dummyNode1.tVersionSent = GetTime(); // should not cause ban if VERSION was sent + ProcessMessage(&dummyNode1, NetMsgType::VERACK, vRecv1, GetTime()); + SendMessages(&dummyNode1); + BOOST_CHECK(dummyNode1.tVersionSent >= 0); + BOOST_CHECK(!dosMan.IsBanned(addr1)); + + // Receive VERACK but no VERSION sent + dummyNode1.fSuccessfullyConnected = false; + dummyNode1.tVersionSent = -1; // should cause disconnect + ProcessMessage(&dummyNode1, NetMsgType::VERACK, vRecv1, GetTime()); + SendMessages(&dummyNode1); + BOOST_CHECK(dummyNode1.tVersionSent < 0); + BOOST_CHECK(dummyNode1.fDisconnect); + + // Receive duplicate VERACK after VERSION sent. fSuccessfullyConnected will already be true. + vRecv1.clear(); + dosMan.ClearBanned(); + CNode dummyNode2(INVALID_SOCKET, addr2, "", true); + dummyNode2.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode2.fSuccessfullyConnected = true; // should cause disconnect if VERSION was already sent + dummyNode2.tVersionSent = GetTime(); + ProcessMessage(&dummyNode2, NetMsgType::VERACK, vRecv1, GetTime()); + SendMessages(&dummyNode2); + BOOST_CHECK(dummyNode2.fSuccessfullyConnected); + BOOST_CHECK(dummyNode2.fDisconnect); + + // Test the disconnect of a peer if the VERACK_TIMEOUT is exceeded + int64_t nStartTime = GetTime(); + + vRecv1.clear(); + dosMan.ClearBanned(); + CNode dummyNode3(INVALID_SOCKET, addr3, "", true); + dummyNode3.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode3.fSuccessfullyConnected = false; + dummyNode3.tVersionSent = nStartTime; + SetMockTime(nStartTime + VERACK_TIMEOUT + 1); // VERACK should not cause disconnect even if timeout exceeded + ProcessMessage(&dummyNode3, NetMsgType::VERACK, vRecv1, GetTime()); + SendMessages(&dummyNode3); + BOOST_CHECK(dummyNode3.tVersionSent >= 0); + BOOST_CHECK(!dosMan.IsBanned(addr3)); + + vRecv1.clear(); + dosMan.ClearBanned(); + CNode dummyNode4(INVALID_SOCKET, addr4, "", true); + dummyNode4.nVersion = 1; + dummyNode4.fSuccessfullyConnected = false; + dummyNode4.tVersionSent = nStartTime; + SetMockTime(nStartTime + VERACK_TIMEOUT); // should not disconnect if timeout not exceeded and no VERACK + ProcessMessage(&dummyNode4, NetMsgType::PING, vRecv1, GetTime()); + BOOST_CHECK(!dummyNode4.fDisconnect); + + vRecv1.clear(); + dosMan.ClearBanned(); + CNode dummyNode4a(INVALID_SOCKET, addr4, "", true); + dummyNode4a.nVersion = 1; + dummyNode4a.fSuccessfullyConnected = false; + dummyNode4a.tVersionSent = nStartTime; + SetMockTime(nStartTime + VERACK_TIMEOUT + 1); // should disconnect if timeout exceeded and no VERACK + ProcessMessage(&dummyNode4a, NetMsgType::PING, vRecv1, GetTime()); + BOOST_CHECK(dummyNode4a.fDisconnect); +} + +BOOST_AUTO_TEST_CASE(bu_version_tests) +{ + // Receive BUVERSION after VERACK sent + vRecv1.clear(); + dosMan.ClearBanned(); + vRecv1 << 8333; + + CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + dummyNode1.fSuccessfullyConnected = true; + dummyNode1.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode1.fVerackSent = true; // should not cause ban if VERACK was sent + dummyNode1.addrFromPort = 0; + ProcessMessage(&dummyNode1, NetMsgType::BUVERSION, vRecv1, GetTime()); + SendMessages(&dummyNode1); + BOOST_CHECK(dummyNode1.fVerackSent); + BOOST_CHECK(!dosMan.IsBanned(addr1)); + + // Receive BUVERSION but no VERACK sent + dummyNode1.fSuccessfullyConnected = true; + dummyNode1.fVerackSent = false; // should cause ban + dummyNode1.addrFromPort = 0; + ProcessMessage(&dummyNode1, NetMsgType::BUVERACK, vRecv1, GetTime()); + SendMessages(&dummyNode1); + BOOST_CHECK(!dummyNode1.fVerackSent); + BOOST_CHECK(dosMan.IsBanned(addr1)); + + // Recieve duplicate BUVERSION. addrFromPort will not be zero + CNode dummyNode2(INVALID_SOCKET, addr2, "", true); + dummyNode2.fSuccessfullyConnected = true; + dummyNode2.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode2.fVerackSent = true; + dummyNode2.addrFromPort = 8333; // should ban because already have received a message + ProcessMessage(&dummyNode2, NetMsgType::BUVERSION, vRecv1, GetTime()); + SendMessages(&dummyNode2); + BOOST_CHECK(dummyNode2.addrFromPort); + BOOST_CHECK(dosMan.IsBanned(addr2)); +} + +BOOST_AUTO_TEST_CASE(bu_verack_tests) +{ + // Receive BUVERACK after BUVERSION sent + vRecv1.clear(); + dosMan.ClearBanned(); + + CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + dummyNode1.fSuccessfullyConnected = true; + dummyNode1.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode1.fBUVersionSent = true; // should not cause ban if BUVERSION was sent + ProcessMessage(&dummyNode1, NetMsgType::BUVERACK, vRecv1, GetTime()); + SendMessages(&dummyNode1); + BOOST_CHECK(dummyNode1.fBUVersionSent); + BOOST_CHECK(!dosMan.IsBanned(addr1)); + + // Receive BUVERACK but no BUVERSION sent + dummyNode1.fSuccessfullyConnected = true; + dummyNode1.fBUVersionSent = false; // should cause ban + ProcessMessage(&dummyNode1, NetMsgType::BUVERACK, vRecv1, GetTime()); + SendMessages(&dummyNode1); + BOOST_CHECK(!dummyNode1.fBUVersionSent); + BOOST_CHECK(dosMan.IsBanned(addr1)); +} + +BOOST_AUTO_TEST_CASE(inv_tests) +{ + // send more INV than the limit of MAX_INV_SZ + vRecv1.clear(); + dosMan.ClearBanned(); + std::vector vInv; + + CInv testINV(MSG_TX, TestBlock1().GetHash()); + for (unsigned int i = 0; i < MAX_INV_SZ; i++) + vInv.push_back(testINV); + + CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + dummyNode1.fSuccessfullyConnected = true; + dummyNode1.nVersion = MIN_PEER_PROTO_VERSION; + vRecv1 << vInv; + ProcessMessage(&dummyNode1, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode1, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode1, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode1, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode1, NetMsgType::INV, vRecv1, GetTime()); + + SendMessages(&dummyNode1); // sending five messages below MAX_INV_SZ should not cause ban + BOOST_CHECK(vInv.size() <= MAX_INV_SZ); + BOOST_CHECK(!dosMan.IsBanned(addr1)); + + + vInv.push_back(testINV); // Add one more INV which should cause a ban + + dummyNode1.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode1.fSuccessfullyConnected = true; + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode1, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode1, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode1, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode1, NetMsgType::INV, vRecv1, GetTime()); + SendMessages(&dummyNode1); // send four messages should not cause ban + BOOST_CHECK(vInv.size() > MAX_INV_SZ); + BOOST_CHECK(!dosMan.IsBanned(addr1)); + + vRecv1 << vInv; + ProcessMessage(&dummyNode1, NetMsgType::INV, vRecv1, GetTime()); + SendMessages(&dummyNode1); // send a fifth message will cause a ban + BOOST_CHECK(vInv.size() > MAX_INV_SZ); + BOOST_CHECK(dosMan.IsBanned(addr1)); + + + // INV with invalid type + vRecv1.clear(); + vInv.clear(); + dosMan.ClearBanned(); + + CInv txINV(MSG_TX, TestBlock1().GetHash()); + CInv blockINV(MSG_BLOCK, TestBlock1().GetHash()); + CInv invalidINV(7, TestBlock1().GetHash()); + for (unsigned int i = 0; i < 10; i++) + { + vInv.push_back(txINV); + vInv.push_back(blockINV); + } + vInv.push_back(invalidINV); // add one invalid + + CNode dummyNode3(INVALID_SOCKET, addr3, "", true); + dummyNode3.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode3.fSuccessfullyConnected = true; + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode3, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode3, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode3, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode3, NetMsgType::INV, vRecv1, GetTime()); + SendMessages(&dummyNode3); // send four messages should not cause ban + BOOST_CHECK(!dosMan.IsBanned(addr3)); + + vRecv1 << vInv; + ProcessMessage(&dummyNode3, NetMsgType::INV, vRecv1, GetTime()); + SendMessages(&dummyNode3); // send a fifth message should cause ban + BOOST_CHECK(dosMan.IsBanned(addr3)); + + + // INV with null hash + vRecv1.clear(); + vInv.clear(); + nullhash.SetNull(); + dosMan.ClearBanned(); + + CInv nullINV(MSG_BLOCK, nullhash); + for (unsigned int i = 0; i < 10; i++) + { + vInv.push_back(txINV); + vInv.push_back(blockINV); + } + vInv.push_back(nullINV); // add one with null hash + + CNode dummyNode5(INVALID_SOCKET, addr5, "", true); + dummyNode5.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode5.fSuccessfullyConnected = true; + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode5, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode5, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode5, NetMsgType::INV, vRecv1, GetTime()); + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode5, NetMsgType::INV, vRecv1, GetTime()); + SendMessages(&dummyNode5); // send four messages should not cause ban + BOOST_CHECK(!dosMan.IsBanned(addr5)); + + vRecv1.clear(); + vRecv1 << vInv; + ProcessMessage(&dummyNode5, NetMsgType::INV, vRecv1, GetTime()); + SendMessages(&dummyNode5); // send a fifth message should cause ban + BOOST_CHECK(dosMan.IsBanned(addr5)); +} + +BOOST_AUTO_TEST_CASE(transaction_tests) +{ + // Transaction tests are handled in transaction_tests.cpp and fully covered there. +} + +BOOST_AUTO_TEST_CASE(block_tests) +{ + // Block tests are handled in checkblock_tests.cpp and fully covered there. +} + + +BOOST_AUTO_TEST_CASE(thinblock_tests) +{ + { + fImporting = false; + fReindex = false; + fIsInitialBlockDownload.store(false); + + CBloomFilter filter; + std::vector vOrphanHashes; + // Create 10 random hashes to seed the orphanhash vector. This way we will create a bloom filter + // with a size of 10 elements. + std::string hash = "3fba505b48865fccda4e248cecc39d5dfbc6b8ef7b4adc9cd27242c1193c714"; + for (int i = 0; i < 10; i++) + { + std::stringstream ss; + ss << i; + hash.append(ss.str()); + uint256 random_hash = uint256S(hash); + vOrphanHashes.push_back(random_hash); + } + std::unique_ptr dummyNodeMem(new CNode(INVALID_SOCKET, addr1, "", true)); + CNode &dummyNode = *dummyNodeMem; + BuildSeededBloomFilter(filter, vOrphanHashes, TestBlock1().GetHash(), &dummyNode, true); + + block = TestBlock1(); + CThinBlock thinblock(block, filter); + CXThinBlock xthinblock(block, &filter); + + /** FILTERSIZEXTHIN tests */ + + CDataStream ssSend(SER_NETWORK, INIT_PROTO_VERSION); + ssSend << (uint32_t)36000; + + dosMan.ClearBanned(); + vRecv1.clear(); + vRecv1 << ssSend; + { + std::unique_ptr dummyNodeAMem(new CNode(INVALID_SOCKET, addr1, "", true)); + CNode &dummyNodeA = *dummyNodeMem; + dummyNodeA.nServices |= NODE_XTHIN; + dummyNodeA.nVersion = MIN_PEER_PROTO_VERSION; + dummyNodeA.fSuccessfullyConnected = true; + ProcessMessage(&dummyNodeA, NetMsgType::FILTERSIZEXTHIN, vRecv1, GetTime()); + BOOST_CHECK(!dummyNodeA.fDisconnect); // node should not be disconnected + } + + dosMan.ClearBanned(); + vRecv1.clear(); + vRecv1 << ssSend; + + { + std::unique_ptr dummyNodeBMem(new CNode(INVALID_SOCKET, addr1, "", true)); + CNode &dummyNodeB = *dummyNodeBMem; + dummyNodeB.nServices |= NODE_BLOOM; + dummyNodeB.nVersion = MIN_PEER_PROTO_VERSION; + dummyNodeB.fSuccessfullyConnected = true; + ProcessMessage(&dummyNodeB, NetMsgType::FILTERSIZEXTHIN, vRecv1, GetTime()); + BOOST_CHECK(dummyNodeB.fDisconnect); // node should be disconnected + } + + dosMan.ClearBanned(); + vRecv1.clear(); + vRecv1 << ssSend; + + { + std::unique_ptr dummyNodeCMem(new CNode(INVALID_SOCKET, addr1, "", true)); + CNode &dummyNodeC = *dummyNodeCMem; + dummyNodeC.nServices |= NODE_XTHIN; + dummyNodeC.nServices |= NODE_BLOOM; + dummyNodeC.nVersion = MIN_PEER_PROTO_VERSION; + dummyNodeC.fSuccessfullyConnected = true; + ProcessMessage(&dummyNodeC, NetMsgType::FILTERSIZEXTHIN, vRecv1, GetTime()); + BOOST_CHECK(!dummyNodeC.fDisconnect); // node should not be disconnected + } + + // Send a filter message indicating a size that is less than the default 36000. + // This should get a disconnect. + CDataStream ssSend2(SER_NETWORK, INIT_PROTO_VERSION); + ssSend2 << (uint32_t)35999; + + dosMan.ClearBanned(); + vRecv1.clear(); + vRecv1 << ssSend2; + + { + std::unique_ptr dummyNodeDMem(new CNode(INVALID_SOCKET, addr1, "", true)); + CNode &dummyNodeD = *dummyNodeDMem; + dummyNodeD.nServices |= NODE_XTHIN; + dummyNodeD.nVersion = MIN_PEER_PROTO_VERSION; + dummyNodeD.fSuccessfullyConnected = true; + ProcessMessage(&dummyNodeD, NetMsgType::FILTERSIZEXTHIN, vRecv1, GetTime()); + BOOST_CHECK(dummyNodeD.fDisconnect); // node should be disconnected + } + + /** XTHINBLOCK message consistency checks */ + + // testing empty missingtx vector + dosMan.ClearBanned(); + CXThinBlock xthin = xthinblock; + xthin.vMissingTx.clear(); // empty the missingtx vector. This should cause an error. + vRecv1.clear(); + vRecv1 << xthin; + + { + CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + dummyNode1.nServices |= NODE_XTHIN; + dummyNode1.nServices |= NODE_BLOOM; + dummyNode1.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode1.fSuccessfullyConnected = true; + ProcessMessage(&dummyNode1, NetMsgType::XTHINBLOCK, vRecv1, GetTime()); + SendMessages(&dummyNode1); + BOOST_CHECK(xthin.vMissingTx.size() == 0); + BOOST_CHECK(dosMan.IsBanned(addr1)); + } + + // test invalid or missing coinbase + dosMan.ClearBanned(); + vRecv1.clear(); + xthin = xthinblock; + xthin.vMissingTx[0] = xthin.vMissingTx[1]; // delete the coinbase. This should cause an error. + vRecv1 << xthin; + + { + CNode dummyNode1a(INVALID_SOCKET, addr1, "", true); + dummyNode1a.nServices |= NODE_XTHIN; + dummyNode1a.nServices |= NODE_BLOOM; + dummyNode1a.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode1a.fSuccessfullyConnected = true; + ProcessMessage(&dummyNode1a, NetMsgType::XTHINBLOCK, vRecv1, GetTime()); + SendMessages(&dummyNode1a); + BOOST_CHECK(!xthin.vMissingTx[0].IsCoinBase()); + BOOST_CHECK(dosMan.IsBanned(addr1)); + } + + // test invalid block header + dosMan.ClearBanned(); + vRecv1.clear(); + xthin = xthinblock; + xthin.header.nBits = 1; // create invalid block header + vRecv1 << xthin; + + CValidationState state; + + { + CNode dummyNode1b(INVALID_SOCKET, addr1, "", true); + dummyNode1b.nServices |= NODE_XTHIN; + dummyNode1b.nServices |= NODE_BLOOM; + dummyNode1b.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode1b.fSuccessfullyConnected = true; + ProcessMessage(&dummyNode1b, NetMsgType::XTHINBLOCK, vRecv1, GetTime()); + SendMessages(&dummyNode1b); + BOOST_CHECK(!CheckBlockHeader(xthin.header, state, true)); + BOOST_CHECK(dosMan.IsBanned(addr1)); + } + /** THINBLOCK message consistency checks */ + + // test empty missingtx vector + dosMan.ClearBanned(); + CThinBlock thin = thinblock; + thin.vMissingTx.clear(); // empty the missingtx vector. This should cause an error. + vRecv2 << thin; + + { + CNode dummyNode2(INVALID_SOCKET, addr2, "", true); + dummyNode2.nServices |= NODE_XTHIN; + dummyNode2.nServices |= NODE_BLOOM; + dummyNode2.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode2.fSuccessfullyConnected = true; + ProcessMessage(&dummyNode2, NetMsgType::THINBLOCK, vRecv2, GetTime()); + SendMessages(&dummyNode2); + BOOST_CHECK(thin.vMissingTx.size() == 0); + BOOST_CHECK(dosMan.IsBanned(addr2)); + } + + // test invalid or missing coinbase + dosMan.ClearBanned(); + vRecv2.clear(); + thin = thinblock; + thin.vMissingTx[0] = thin.vMissingTx[1]; // delete the coinbase. This should cause an error. + vRecv2 << thin; + + { + CNode dummyNode2a(INVALID_SOCKET, addr2, "", true); + dummyNode2a.nServices |= NODE_XTHIN; + dummyNode2a.nServices |= NODE_BLOOM; + dummyNode2a.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode2a.fSuccessfullyConnected = true; + ProcessMessage(&dummyNode2a, NetMsgType::THINBLOCK, vRecv2, GetTime()); + SendMessages(&dummyNode2a); + BOOST_CHECK(!thin.vMissingTx[0].IsCoinBase()); + BOOST_CHECK(dosMan.IsBanned(addr2)); + } + + // create invalid block header + dosMan.ClearBanned(); + vRecv2.clear(); + thin = thinblock; + thin.header.nBits = 1; + vRecv2 << thin; + + { + CNode dummyNode2b(INVALID_SOCKET, addr2, "", true); + dummyNode2b.nServices |= NODE_XTHIN; + dummyNode2b.nServices |= NODE_BLOOM; + dummyNode2b.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode2b.fSuccessfullyConnected = true; + ProcessMessage(&dummyNode2b, NetMsgType::THINBLOCK, vRecv2, GetTime()); + SendMessages(&dummyNode2b); + BOOST_CHECK(!CheckBlockHeader(thin.header, state, true)); + BOOST_CHECK(dosMan.IsBanned(addr2)); + } + + + /** XBLOCKTX message consistency checks */ + + // test null hash + CBlock block3 = TestBlock1(); + + dosMan.ClearBanned(); + nullhash.SetNull(); + CXThinBlockTx xblocktx(nullhash, block3.vtx); + vRecv3 << xblocktx; + + { + CNode dummyNode3(INVALID_SOCKET, addr3, "", true); + dummyNode3.nServices |= NODE_XTHIN; + dummyNode3.nServices |= NODE_BLOOM; + dummyNode3.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode3.fSuccessfullyConnected = true; + ProcessMessage(&dummyNode3, NetMsgType::XBLOCKTX, vRecv3, GetTime()); + SendMessages(&dummyNode3); + BOOST_CHECK(nullhash.IsNull()); + BOOST_CHECK(dosMan.IsBanned(addr3)); + } + + // test no txns in xblocktx + dosMan.ClearBanned(); + vRecv3.clear(); + std::vector vTxEmpty; + CXThinBlockTx xblocktx2(block3.GetHash(), vTxEmpty); + vRecv3 << xblocktx2; + + { + CNode dummyNode3a(INVALID_SOCKET, addr3, "", true); + dummyNode3a.nServices |= NODE_XTHIN; + dummyNode3a.nServices |= NODE_BLOOM; + dummyNode3a.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode3a.fSuccessfullyConnected = true; + ProcessMessage(&dummyNode3a, NetMsgType::XBLOCKTX, vRecv3, GetTime()); + SendMessages(&dummyNode3a); + BOOST_CHECK(vTxEmpty.size() == 0); + BOOST_CHECK(dosMan.IsBanned(addr3)); + } + + /** GET_XBLOCKTX message consistency checks */ + + // test null hash + dosMan.ClearBanned(); + nullhash.SetNull(); + std::set setHashesToRequest; + setHashesToRequest.insert(1); // add a hash so that we are not empty + CXRequestThinBlockTx get_xblocktx(nullhash, setHashesToRequest); + vRecv4 << get_xblocktx; + + { + CNode dummyNode4(INVALID_SOCKET, addr4, "", true); + dummyNode4.nServices |= NODE_XTHIN; + dummyNode4.nServices |= NODE_BLOOM; + dummyNode4.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode4.fSuccessfullyConnected = true; + ProcessMessage(&dummyNode4, NetMsgType::GET_XBLOCKTX, vRecv4, GetTime()); + SendMessages(&dummyNode4); + BOOST_CHECK(nullhash.IsNull()); + BOOST_CHECK(dosMan.IsBanned(addr4)); + } + + // test empty setHashesToRequest + dosMan.ClearBanned(); + vRecv4.clear(); + setHashesToRequest.clear(); // clear the set + CXRequestThinBlockTx get_xblocktx2(block3.GetHash(), setHashesToRequest); + vRecv4 << get_xblocktx2; + + { + std::unique_ptr dummyNode4aMem(new CNode(INVALID_SOCKET, addr4, "", true)); + CNode &dummyNode4a = *dummyNode4aMem; + dummyNode4a.nServices |= NODE_XTHIN; + dummyNode4a.nServices |= NODE_BLOOM; + dummyNode4a.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode4a.fSuccessfullyConnected = true; + ProcessMessage(&dummyNode4a, NetMsgType::GET_XBLOCKTX, vRecv4, GetTime()); + SendMessages(&dummyNode4a); + BOOST_CHECK(setHashesToRequest.empty()); + BOOST_CHECK(dosMan.IsBanned(addr4)); + + + /** GET_XTHIN message consistency checks */ + + // test get_xthin with null hash + dosMan.ClearBanned(); + nullhash.SetNull(); + CInv inv(MSG_XTHINBLOCK, nullhash); + CBloomFilter filterMemPool; + BuildSeededBloomFilter(filterMemPool, vOrphanHashes, inv.hash, &dummyNode4a, true); + vRecv5 << inv; + vRecv5 << filterMemPool; + + std::unique_ptr dummyNode5Mem(new CNode(INVALID_SOCKET, addr5, "", true)); + CNode &dummyNode5 = *dummyNode5Mem; + dummyNode5.nServices |= NODE_XTHIN; + dummyNode5.nServices |= NODE_BLOOM; + dummyNode5.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode5.fSuccessfullyConnected = true; + ProcessMessage(&dummyNode5, NetMsgType::GET_XTHIN, vRecv5, GetTime()); + SendMessages(&dummyNode5); + BOOST_CHECK(nullhash.IsNull()); + BOOST_CHECK(dosMan.IsBanned(addr5)); + + // test get_xthin with invalid message type + dosMan.ClearBanned(); + vRecv5.clear(); + CInv inv2(15, block3.GetHash()); // invalid type + CBloomFilter filterMemPool2; + BuildSeededBloomFilter(filterMemPool2, vOrphanHashes, inv2.hash, &dummyNode5, true); + vRecv5 << inv2; + vRecv5 << filterMemPool2; + + std::unique_ptr dummyNode5aMem(new CNode(INVALID_SOCKET, addr5, "", true)); + CNode &dummyNode5a = *dummyNode5aMem; + dummyNode5a.nServices |= NODE_XTHIN; + dummyNode5a.nServices |= NODE_BLOOM; + dummyNode5a.nVersion = MIN_PEER_PROTO_VERSION; + dummyNode5a.fSuccessfullyConnected = true; + ProcessMessage(&dummyNode5a, NetMsgType::GET_XTHIN, vRecv5, GetTime()); + SendMessages(&dummyNode5a); + BOOST_CHECK(inv2.type != MSG_THINBLOCK && inv2.type != MSG_XTHINBLOCK); + BOOST_CHECK(dosMan.IsBanned(addr5)); + } + + + /* Thinblock memory exhaustion attack 1 */ + + // test a single valid thinblock reconstruction that goes over the limit. + // result: the peer should have it data cleared and node should be disconnected. + dosMan.ClearBanned(); + CXThinBlock xthin2 = xthinblock; + CThinBlock thin2 = thinblock; + + std::unique_ptr dummyNode6Mem(new CNode(INVALID_SOCKET, addr1, "", true)); + CNode &dummyNode6 = *dummyNode6Mem; + + // The number of tx bytes in this block is 3784 bytes. In order for the node to be disconnected + // we have to make the maxAllowedSize be less than 3784/maxMessageSizeMultiplier (maxMessageSizeMultiplier = + // 16). + // Therefore the excesssiveBlockSize must be less than 236.5 inorder to trigger an oversized block and susequent + // disconnection. + uint64_t old_excessiveBlockSize = excessiveBlockSize; + excessiveBlockSize = 234; + + // Add the node to vNodes and also we need a thinblockinflight entry + dummyNode6.mapThinBlocksInFlight[TestBlock1().GetHash()].nRequestTime = GetTime(); + vNodes.push_back(&dummyNode6); + + // Process an xthinblock + vRecv1.clear(); + vRecv1 << xthin; + dummyNode6.fDisconnect = false; + xthin2.process(&dummyNode6, vRecv1.size(), NetMsgType::XTHINBLOCK); + BOOST_CHECK(dummyNode6.fDisconnect); // node should be disconnected + BOOST_CHECK_EQUAL(0, dummyNode6.nLocalThinBlockBytes); + BOOST_CHECK_EQUAL(-1, dummyNode6.thinBlockWaitingForTxns); + BOOST_CHECK(dummyNode6.thinBlock.IsNull()); + BOOST_CHECK(dummyNode6.xThinBlockHashes.empty()); + BOOST_CHECK(dummyNode6.thinBlockHashes.empty()); + + // clean up vNodes and mapthinblocksinflight + vNodes.pop_back(); + dummyNode6.mapThinBlocksInFlight.erase(TestBlock1().GetHash()); + + // Add the node to vNodes and also we need a thinblockinflight entry + dummyNode6.mapThinBlocksInFlight[TestBlock1().GetHash()].nRequestTime = GetTime(); + vNodes.push_back(&dummyNode6); + + // Process a regular thinblock + vRecv1.clear(); + vRecv1 << thin; + dummyNode6.fDisconnect = false; + thin2.process(&dummyNode6, vRecv1.size()); + BOOST_CHECK(dummyNode6.fDisconnect); // node should be disconnected + BOOST_CHECK_EQUAL(0, dummyNode6.nLocalThinBlockBytes); + BOOST_CHECK_EQUAL(-1, dummyNode6.thinBlockWaitingForTxns); + BOOST_CHECK(dummyNode6.thinBlock.IsNull()); + BOOST_CHECK(dummyNode6.xThinBlockHashes.empty()); + BOOST_CHECK(dummyNode6.thinBlockHashes.empty()); + + // clean up vNodes and mapthinblocksinflight + vNodes.pop_back(); + dummyNode6.mapThinBlocksInFlight.erase(TestBlock1().GetHash()); + + /* Thinblock memory exhaustion attack 2 */ + + // test correct disconnection of a multiple valid thinblock reconstruction that goes over the limit. + // result: the peer with largest thinblock set of data should have it data cleared + // and node should be disconnected. + + dosMan.ClearBanned(); + CXThinBlock xthin3 = xthinblock; + + std::unique_ptr dummyNode7Mem(new CNode(INVALID_SOCKET, addr2, "", true)); + CNode &dummyNode7 = *dummyNode7Mem; + std::unique_ptr dummyNode8Mem(new CNode(INVALID_SOCKET, addr3, "", true)); + CNode &dummyNode8 = *dummyNode8Mem; + std::unique_ptr dummyNode9Mem(new CNode(INVALID_SOCKET, addr4, "", true)); + CNode &dummyNode9 = *dummyNode9Mem; + + // The number of tx bytes in this block is 3784 bytes. In order for the node to be disconnected + // we have to make the maxAllowedSize be less than 3784/maxMessageSizeMultiplier (maxMessageSizeMultiplier = + // 16). + // Therefore the excesssiveBlockSize must be less than 236.5 inorder to trigger an oversized block and susequent + // disconnection. + excessiveBlockSize = 234; + + // Add the node to vNodes and also we need a thinblockinflight entry + dummyNode6.mapThinBlocksInFlight[TestBlock1().GetHash()].nRequestTime = GetTime(); + vNodes.push_back(&dummyNode6); + dummyNode7.mapThinBlocksInFlight[TestBlock1().GetHash()].nRequestTime = GetTime(); + vNodes.push_back(&dummyNode7); + dummyNode8.mapThinBlocksInFlight[TestBlock1().GetHash()].nRequestTime = GetTime(); + vNodes.push_back(&dummyNode8); + dummyNode9.mapThinBlocksInFlight[TestBlock1().GetHash()].nRequestTime = GetTime(); + vNodes.push_back(&dummyNode9); + + // manually set the nLocalThinBlockBytes to be lower than the actual bytes of the thinblock that we will + // use to test the over limit condition. Also set the global bytes to be the sum of all current nodes. + thindata.ResetThinBlockBytes(); + thindata.AddThinBlockBytes(100, &dummyNode7); + thindata.AddThinBlockBytes(110, &dummyNode8); + thindata.AddThinBlockBytes(120, &dummyNode9); + + // Process an xthinblock which will be the largest over limit and will be the one that gets disconnected. + vRecv1.clear(); + vRecv1 << xthin; + dummyNode6.fDisconnect = false; + xthin3.process(&dummyNode6, vRecv1.size(), NetMsgType::XTHINBLOCK); + + BOOST_CHECK(!dummyNode7.fDisconnect); // node should *not* be disconnected + BOOST_CHECK_EQUAL(100, dummyNode7.nLocalThinBlockBytes); + BOOST_CHECK(!dummyNode8.fDisconnect); // node should *not* be disconnected + BOOST_CHECK_EQUAL(110, dummyNode8.nLocalThinBlockBytes); + BOOST_CHECK(!dummyNode9.fDisconnect); // node should *not* be disconnected + BOOST_CHECK_EQUAL(120, dummyNode9.nLocalThinBlockBytes); + + BOOST_CHECK(dummyNode6.fDisconnect); // node should be disconnected + BOOST_CHECK_EQUAL(0, dummyNode6.nLocalThinBlockBytes); + BOOST_CHECK_EQUAL(-1, dummyNode6.thinBlockWaitingForTxns); + BOOST_CHECK(dummyNode6.thinBlock.IsNull()); + BOOST_CHECK(dummyNode6.xThinBlockHashes.empty()); + BOOST_CHECK(dummyNode6.thinBlockHashes.empty()); + + // clean up vNodes and mapthinblocksinflight + vNodes.pop_back(); + dummyNode6.mapThinBlocksInFlight.erase(TestBlock1().GetHash()); + vNodes.pop_back(); + dummyNode7.mapThinBlocksInFlight.erase(TestBlock1().GetHash()); + vNodes.pop_back(); + dummyNode8.mapThinBlocksInFlight.erase(TestBlock1().GetHash()); + vNodes.pop_back(); + dummyNode9.mapThinBlocksInFlight.erase(TestBlock1().GetHash()); + + /* Thinblock memory exhaustion attack 3 */ + + // test correct disconnection of a multiple valid thinblock reconstruction that goes over the limit. + // However here, the last thinblock although causing the limit to be exceeded is not the largest. + // result: the peer with largest thinblock set of data should have it data cleared + // and node should be disconnected. + + dosMan.ClearBanned(); + CXThinBlock xthin4 = xthinblock; + + // This time we don't want the xthinblock to cause an overlimit but have some other node disconnected. + // So we use a 1000 excessive size which gives us a 16 * 1000 byte limit. + excessiveBlockSize = 234; + + // Add the node to vNodes and also we need a thinblockinflight entry + dummyNode6.mapThinBlocksInFlight[TestBlock1().GetHash()].nRequestTime = GetTime(); + vNodes.push_back(&dummyNode6); + dummyNode7.mapThinBlocksInFlight[TestBlock1().GetHash()].nRequestTime = GetTime(); + vNodes.push_back(&dummyNode7); + dummyNode8.mapThinBlocksInFlight[TestBlock1().GetHash()].nRequestTime = GetTime(); + vNodes.push_back(&dummyNode8); + dummyNode9.mapThinBlocksInFlight[TestBlock1().GetHash()].nRequestTime = GetTime(); + vNodes.push_back(&dummyNode9); + + // manually set two of the nLocalThinBlockBytes to be higher than the actual bytes of the thinblock that we will + // use to test the over limit condition. Also set the global bytes to be the sum of all current nodes. + thindata.ResetThinBlockBytes(); + dummyNode7.nLocalThinBlockBytes = 0; + dummyNode8.nLocalThinBlockBytes = 0; + dummyNode9.nLocalThinBlockBytes = 0; + thindata.AddThinBlockBytes(3000, &dummyNode7); + thindata.AddThinBlockBytes(600, &dummyNode8); + thindata.AddThinBlockBytes(100, &dummyNode9); + + // Process an xthinblock which will also be the over limit and will cause the largest block to disconnect + // which in this case is dummyNode7. As it continues to process it (dummyNode6) will also go over the limit + // and cause itself to be disconnected. + vRecv1.clear(); + vRecv1 << xthin4; + dummyNode6.fDisconnect = false; + xthin4.process(&dummyNode6, vRecv1.size(), NetMsgType::XTHINBLOCK); + BOOST_CHECK(!dummyNode8.fDisconnect); // node should *not* be disconnected + BOOST_CHECK_EQUAL(600, dummyNode8.nLocalThinBlockBytes); + BOOST_CHECK(!dummyNode9.fDisconnect); // node should *not* be disconnected + BOOST_CHECK_EQUAL(100, dummyNode9.nLocalThinBlockBytes); + + BOOST_CHECK(dummyNode6.fDisconnect); // node should *not* be disconnected + BOOST_CHECK_EQUAL(0, dummyNode6.nLocalThinBlockBytes); + BOOST_CHECK_EQUAL(-1, dummyNode6.thinBlockWaitingForTxns); + BOOST_CHECK(dummyNode6.thinBlock.IsNull()); + BOOST_CHECK(dummyNode6.xThinBlockHashes.empty()); + BOOST_CHECK(dummyNode6.thinBlockHashes.empty()); + + BOOST_CHECK(dummyNode7.fDisconnect); // node should be disconnected + BOOST_CHECK_EQUAL(0, dummyNode7.nLocalThinBlockBytes); + BOOST_CHECK_EQUAL(-1, dummyNode7.thinBlockWaitingForTxns); + BOOST_CHECK(dummyNode7.thinBlock.IsNull()); + BOOST_CHECK(dummyNode7.xThinBlockHashes.empty()); + BOOST_CHECK(dummyNode7.thinBlockHashes.empty()); + + // clean up vNodes and mapthinblocksinflight + vNodes.pop_back(); + dummyNode6.mapThinBlocksInFlight.erase(TestBlock1().GetHash()); + vNodes.pop_back(); + dummyNode7.mapThinBlocksInFlight.erase(TestBlock1().GetHash()); + vNodes.pop_back(); + dummyNode8.mapThinBlocksInFlight.erase(TestBlock1().GetHash()); + vNodes.pop_back(); + dummyNode9.mapThinBlocksInFlight.erase(TestBlock1().GetHash()); + + + /* + * Test the disconnection of a peers with thinblocks in flight that has gone over the timeout limit + */ + { + int64_t nStartTime = GetTime(); + uint256 hash1 = uint256S("3fba505b48865fccda4e248cecc39d5dfbc6b8ef7b4adc9cd27242c1193c7141"); + uint256 hash2 = uint256S("3fba505b48865fccda4e248cecc39d5dfbc6b8ef7b4adc9cd27242c1193c7142"); + + CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + dummyNode1.fDisconnect = false; + dummyNode1.fSuccessfullyConnected = true; + + CNode dummyNode2(INVALID_SOCKET, addr2, "", true); + dummyNode2.fDisconnect = false; + dummyNode2.fSuccessfullyConnected = true; + + SetMockTime(nStartTime); + AddThinBlockInFlight(&dummyNode1, hash1); + SetMockTime(nStartTime + 1); + AddThinBlockInFlight(&dummyNode1, hash2); + SetMockTime(nStartTime + 1); + AddThinBlockInFlight(&dummyNode2, hash1); + + // Move clock forward to the boundary of the timeout interval + // No nodes should be disconnected. + SetMockTime(nStartTime + (6 * blkReqRetryInterval / 1000000)); + SendMessages(&dummyNode1); + SendMessages(&dummyNode2); + BOOST_CHECK(!dummyNode1.fDisconnect); + BOOST_CHECK(!dummyNode2.fDisconnect); + + + // Move clock forward to 1 second past the boundary of the timeout interval + // DummyNode1 should be disconnected + // DummyNode2 should still be connected because it was added one second later. + SetMockTime(nStartTime + (6 * blkReqRetryInterval / 1000000) + 1); + SendMessages(&dummyNode1); + SendMessages(&dummyNode2); + BOOST_CHECK(dummyNode1.fDisconnect); + BOOST_CHECK(!dummyNode2.fDisconnect); + + // Move clock forward to 1 second past the boundary of the timeout interval + // DummyNode2 should now be disconnected + SetMockTime(nStartTime + (6 * blkReqRetryInterval / 1000000) + 2); + SendMessages(&dummyNode2); + BOOST_CHECK(dummyNode2.fDisconnect); + } + + excessiveBlockSize = old_excessiveBlockSize; // reset + + // cleanup received queues + vRecv1.clear(); + vRecv2.clear(); + vRecv3.clear(); + vRecv4.clear(); + vRecv5.clear(); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/fork_tests.cpp b/src/test/fork_tests.cpp new file mode 100644 index 00000000..c53c9ea7 --- /dev/null +++ b/src/test/fork_tests.cpp @@ -0,0 +1,55 @@ +// Copyright (c) 2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "addrman.h" +#include "chainparams.h" +#include "hash.h" +#include "net.h" +#include "serialize.h" +#include "streams.h" +#include "test/test_bitcoin.h" +#include +#include + + +BOOST_FIXTURE_TEST_SUITE(fork_test, TestingSetup) + +// must be >= 12 +#define SZ 20 + +BOOST_AUTO_TEST_CASE(fork_trigger) +{ + CChain test; + + CBlockIndex bi[SZ]; + + for (int i = 0; i < SZ; i++) + { + if (i) + bi[i].pprev = &bi[i - 1]; + bi[i].nHeight = i; + bi[i].nTime = i; + } + + for (int i = 0; i < SZ; i++) + { + BOOST_CHECK(bi[i].forkAtNextBlock(SZ + 1) == false); + BOOST_CHECK(bi[i].forkActivated(SZ + 1) == false); + BOOST_CHECK(bi[i].forkActivateNow(SZ + 1) == false); + } + + for (int i = 0; i < SZ; i++) + { + BOOST_CHECK(bi[i].forkAtNextBlock(0) == false); + BOOST_CHECK(bi[i].forkActivated(0) == false); + BOOST_CHECK(bi[i].forkActivateNow(0) == false); + } + + BOOST_CHECK(bi[SZ - 1].forkActivated(1) == true); + BOOST_CHECK(bi[SZ - 1].forkAtNextBlock(1) == false); + + BOOST_CHECK(bi[SZ - 1].forkAtNextBlock(SZ - 6) == true); + BOOST_CHECK(bi[SZ - 1].forkAtNextBlock(SZ - 5) == false); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 169b3943..a48442d9 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -1,166 +1,213 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "test/test_bitcoin.h" +#include "util.h" + +#include +#include + #include +#include #include -#include "util.h" +BOOST_FIXTURE_TEST_SUITE(getarg_tests, BasicTestingSetup) -BOOST_AUTO_TEST_SUITE(getarg_tests) +enum Kind +{ + BITCOIND = 0, + CONFIGFILE = 1, + BITCOIN_CLI = 2 +}; -static void -ResetArgs(const std::string& strArg) +static void ResetArgs(const std::string &strArg, Kind kind = BITCOIND) { std::vector vecArg; - boost::split(vecArg, strArg, boost::is_space(), boost::token_compress_on); + if (strArg.size()) + boost::split(vecArg, strArg, boost::is_space(), boost::token_compress_on); // Insert dummy executable name: vecArg.insert(vecArg.begin(), "testbitcoin"); // Convert to char*: - std::vector vecChar; - for (auto& s: vecArg) + std::vector vecChar; + BOOST_FOREACH (std::string &s, vecArg) vecChar.push_back(s.c_str()); - ParseParameters(vecChar.size(), &vecChar[0]); + if (kind == CONFIGFILE) + ParseParameters(vecChar.size(), &vecChar[0], AllowedArgs::ConfigFile(&tweaks)); + else if (kind == BITCOIND) + ParseParameters(vecChar.size(), &vecChar[0], AllowedArgs::Bitcoind(&tweaks)); + else + ParseParameters(vecChar.size(), &vecChar[0], AllowedArgs::BitcoinCli()); } BOOST_AUTO_TEST_CASE(boolarg) { - ResetArgs("-foo"); - BOOST_CHECK(GetBoolArg("-foo")); - BOOST_CHECK(GetBoolArg("-foo", false)); - BOOST_CHECK(GetBoolArg("-foo", true)); + ResetArgs("-listen"); + BOOST_CHECK(GetBoolArg("-listen", false)); + BOOST_CHECK(GetBoolArg("-listen", true)); - BOOST_CHECK(!GetBoolArg("-fo")); BOOST_CHECK(!GetBoolArg("-fo", false)); BOOST_CHECK(GetBoolArg("-fo", true)); - BOOST_CHECK(!GetBoolArg("-fooo")); BOOST_CHECK(!GetBoolArg("-fooo", false)); BOOST_CHECK(GetBoolArg("-fooo", true)); - ResetArgs("-foo=0"); - BOOST_CHECK(!GetBoolArg("-foo")); - BOOST_CHECK(!GetBoolArg("-foo", false)); - BOOST_CHECK(!GetBoolArg("-foo", true)); + for (auto strValue : std::list{"0", "f", "n", "false", "no"}) + { + ResetArgs("-listen=" + strValue); + BOOST_CHECK(!GetBoolArg("-listen", false)); + BOOST_CHECK(!GetBoolArg("-listen", true)); + } - ResetArgs("-foo=1"); - BOOST_CHECK(GetBoolArg("-foo")); - BOOST_CHECK(GetBoolArg("-foo", false)); - BOOST_CHECK(GetBoolArg("-foo", true)); + for (auto strValue : std::list{"", "1", "t", "y", "true", "yes"}) + { + ResetArgs("-listen=" + strValue); + BOOST_CHECK(GetBoolArg("-listen", false)); + BOOST_CHECK(GetBoolArg("-listen", true)); + } // New 0.6 feature: auto-map -nosomething to !-something: - ResetArgs("-nofoo"); - BOOST_CHECK(!GetBoolArg("-foo")); - BOOST_CHECK(!GetBoolArg("-foo", false)); - BOOST_CHECK(!GetBoolArg("-foo", true)); - - ResetArgs("-nofoo=1"); - BOOST_CHECK(!GetBoolArg("-foo")); - BOOST_CHECK(!GetBoolArg("-foo", false)); - BOOST_CHECK(!GetBoolArg("-foo", true)); - - ResetArgs("-foo -nofoo"); // -foo should win - BOOST_CHECK(GetBoolArg("-foo")); - BOOST_CHECK(GetBoolArg("-foo", false)); - BOOST_CHECK(GetBoolArg("-foo", true)); - - ResetArgs("-foo=1 -nofoo=1"); // -foo should win - BOOST_CHECK(GetBoolArg("-foo")); - BOOST_CHECK(GetBoolArg("-foo", false)); - BOOST_CHECK(GetBoolArg("-foo", true)); - - ResetArgs("-foo=0 -nofoo=0"); // -foo should win - BOOST_CHECK(!GetBoolArg("-foo")); - BOOST_CHECK(!GetBoolArg("-foo", false)); - BOOST_CHECK(!GetBoolArg("-foo", true)); + ResetArgs("-nolisten"); + BOOST_CHECK(!GetBoolArg("-listen", false)); + BOOST_CHECK(!GetBoolArg("-listen", true)); + + ResetArgs("-nolisten=1"); + BOOST_CHECK(!GetBoolArg("-listen", false)); + BOOST_CHECK(!GetBoolArg("-listen", true)); + + ResetArgs("-listen -nolisten"); // -nolisten should win + BOOST_CHECK(!GetBoolArg("-listen", false)); + BOOST_CHECK(!GetBoolArg("-listen", true)); + + ResetArgs("-listen=1 -nolisten=1"); // -nolisten should win + BOOST_CHECK(!GetBoolArg("-listen", false)); + BOOST_CHECK(!GetBoolArg("-listen", true)); + + ResetArgs("-listen=0 -nolisten=0"); // -nolisten=0 should win + BOOST_CHECK(GetBoolArg("-listen", false)); + BOOST_CHECK(GetBoolArg("-listen", true)); // New 0.6 feature: treat -- same as -: - ResetArgs("--foo=1"); - BOOST_CHECK(GetBoolArg("-foo")); - BOOST_CHECK(GetBoolArg("-foo", false)); - BOOST_CHECK(GetBoolArg("-foo", true)); + ResetArgs("--listen=1"); + BOOST_CHECK(GetBoolArg("-listen", false)); + BOOST_CHECK(GetBoolArg("-listen", true)); - ResetArgs("--nofoo=1"); - BOOST_CHECK(!GetBoolArg("-foo")); - BOOST_CHECK(!GetBoolArg("-foo", false)); - BOOST_CHECK(!GetBoolArg("-foo", true)); + ResetArgs("--nolisten=1"); + BOOST_CHECK(!GetBoolArg("-listen", false)); + BOOST_CHECK(!GetBoolArg("-listen", true)); + BOOST_CHECK_THROW(ResetArgs("-listen=text"), std::runtime_error); } BOOST_AUTO_TEST_CASE(stringarg) { ResetArgs(""); - BOOST_CHECK_EQUAL(GetArg("-foo", ""), ""); - BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "eleven"); + BOOST_CHECK_EQUAL(GetArg("-uacomment", ""), ""); + BOOST_CHECK_EQUAL(GetArg("-uacomment", "eleven"), "eleven"); - ResetArgs("-foo -bar"); - BOOST_CHECK_EQUAL(GetArg("-foo", ""), ""); - BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), ""); + ResetArgs("-connect -listen"); // -connect is an optional string argument + BOOST_CHECK_EQUAL(GetArg("-connect", ""), ""); + BOOST_CHECK_EQUAL(GetArg("-connect", "eleven"), ""); - ResetArgs("-foo="); - BOOST_CHECK_EQUAL(GetArg("-foo", ""), ""); - BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), ""); + ResetArgs("-connect="); + BOOST_CHECK_EQUAL(GetArg("-connect", ""), ""); + BOOST_CHECK_EQUAL(GetArg("-connect", "eleven"), ""); - ResetArgs("-foo=11"); - BOOST_CHECK_EQUAL(GetArg("-foo", ""), "11"); - BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "11"); + ResetArgs("-uacomment=11"); + BOOST_CHECK_EQUAL(GetArg("-uacomment", ""), "11"); + BOOST_CHECK_EQUAL(GetArg("-uacomment", "eleven"), "11"); - ResetArgs("-foo=eleven"); - BOOST_CHECK_EQUAL(GetArg("-foo", ""), "eleven"); - BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "eleven"); + ResetArgs("-uacomment=eleven"); + BOOST_CHECK_EQUAL(GetArg("-uacomment", ""), "eleven"); + BOOST_CHECK_EQUAL(GetArg("-uacomment", "eleven"), "eleven"); + BOOST_CHECK_THROW(ResetArgs("-uacomment"), std::runtime_error); + BOOST_CHECK_THROW(ResetArgs("-uacomment="), std::runtime_error); } BOOST_AUTO_TEST_CASE(intarg) { ResetArgs(""); - BOOST_CHECK_EQUAL(GetArg("-foo", 11), 11); - BOOST_CHECK_EQUAL(GetArg("-foo", 0), 0); + BOOST_CHECK_EQUAL(GetArg("-maxconnections", 11), 11); + BOOST_CHECK_EQUAL(GetArg("-maxconnections", 0), 0); + + ResetArgs("-maxconnections"); // -maxconnections is an optional int argument + BOOST_CHECK_EQUAL(GetArg("-maxconnections", 11), 0); - ResetArgs("-foo -bar"); - BOOST_CHECK_EQUAL(GetArg("-foo", 11), 0); - BOOST_CHECK_EQUAL(GetArg("-bar", 11), 0); + ResetArgs("-maxconnections=11 -maxreceivebuffer=12"); + BOOST_CHECK_EQUAL(GetArg("-maxconnections", 0), 11); + BOOST_CHECK_EQUAL(GetArg("-maxreceivebuffer", 11), 12); - ResetArgs("-foo=11 -bar=12"); - BOOST_CHECK_EQUAL(GetArg("-foo", 0), 11); - BOOST_CHECK_EQUAL(GetArg("-bar", 11), 12); + ResetArgs("-par=-1"); + BOOST_CHECK_EQUAL(GetArg("-par", 0), -1); - ResetArgs("-foo=NaN -bar=NotANumber"); - BOOST_CHECK_EQUAL(GetArg("-foo", 1), 0); - BOOST_CHECK_EQUAL(GetArg("-bar", 11), 0); + BOOST_CHECK_THROW(ResetArgs("-maxreceivebuffer"), std::runtime_error); + BOOST_CHECK_THROW(ResetArgs("-maxreceivebuffer="), std::runtime_error); + BOOST_CHECK_THROW(ResetArgs("-maxreceivebuffer=NaN"), std::runtime_error); } BOOST_AUTO_TEST_CASE(doubledash) { - ResetArgs("--foo"); - BOOST_CHECK_EQUAL(GetBoolArg("-foo"), true); + ResetArgs("--listen"); + BOOST_CHECK_EQUAL(GetBoolArg("-listen", false), true); - ResetArgs("--foo=verbose --bar=1"); - BOOST_CHECK_EQUAL(GetArg("-foo", ""), "verbose"); - BOOST_CHECK_EQUAL(GetArg("-bar", 0), 1); + ResetArgs("--uacomment=verbose --maxconnections=1"); + BOOST_CHECK_EQUAL(GetArg("-uacomment", ""), "verbose"); + BOOST_CHECK_EQUAL(GetArg("-maxconnections", 0), 1); } BOOST_AUTO_TEST_CASE(boolargno) { - ResetArgs("-nofoo"); - BOOST_CHECK(!GetBoolArg("-foo")); - BOOST_CHECK(!GetBoolArg("-foo", true)); - BOOST_CHECK(!GetBoolArg("-foo", false)); - - ResetArgs("-nofoo=1"); - BOOST_CHECK(!GetBoolArg("-foo")); - BOOST_CHECK(!GetBoolArg("-foo", true)); - BOOST_CHECK(!GetBoolArg("-foo", false)); - - ResetArgs("-nofoo=0"); - BOOST_CHECK(GetBoolArg("-foo")); - BOOST_CHECK(GetBoolArg("-foo", true)); - BOOST_CHECK(GetBoolArg("-foo", false)); - - ResetArgs("-foo --nofoo"); - BOOST_CHECK(GetBoolArg("-foo")); - - ResetArgs("-nofoo -foo"); // foo always wins: - BOOST_CHECK(GetBoolArg("-foo")); + ResetArgs("-nolisten"); + BOOST_CHECK(!GetBoolArg("-listen", true)); + BOOST_CHECK(!GetBoolArg("-listen", false)); + + ResetArgs("-nolisten=1"); + BOOST_CHECK(!GetBoolArg("-listen", true)); + BOOST_CHECK(!GetBoolArg("-listen", false)); + + ResetArgs("-nolisten=0"); + BOOST_CHECK(GetBoolArg("-listen", true)); + BOOST_CHECK(GetBoolArg("-listen", false)); + + ResetArgs("-listen --nolisten"); // --nolisten should win + BOOST_CHECK(!GetBoolArg("-listen", true)); + BOOST_CHECK(!GetBoolArg("-listen", false)); + + ResetArgs("-nolisten -listen"); // -listen always wins: + BOOST_CHECK(GetBoolArg("-listen", true)); + BOOST_CHECK(GetBoolArg("-listen", false)); +} + +BOOST_AUTO_TEST_CASE(tweakArgs) +{ + ResetArgs("-mining.comment=I_Am_A_Meat_Popsicle -mining.coinbaseReserve=250 -wallet.maxTxFee=0.001"); + BOOST_CHECK_EQUAL(GetArg("-mining.comment", "foo"), "I_Am_A_Meat_Popsicle"); + BOOST_CHECK_EQUAL(GetArg("-mining.coinbaseReserve", 100), 250); + BOOST_CHECK_EQUAL(GetArg("-wallet.maxTxFee", ""), "0.001"); + + // Test ConfigFile accepts tweaks + ResetArgs("-mining.comment=I_Am_A_Meat_Popsicle -mining.coinbaseReserve=250 -wallet.maxTxFee=0.001", CONFIGFILE); + BOOST_CHECK_EQUAL(GetArg("-mining.comment", "foo"), "I_Am_A_Meat_Popsicle"); + BOOST_CHECK_EQUAL(GetArg("-mining.coinbaseReserve", 100), 250); + BOOST_CHECK_EQUAL(GetArg("-wallet.maxTxFee", ""), "0.001"); + + // Test ConfigFile rejects unknown tweaks + BOOST_CHECK_THROW(ResetArgs("-some.tweak=something", CONFIGFILE), std::runtime_error); + + // Test bitcoin-cli accepts unknown tweaks + ResetArgs("-some.tweak=something", BITCOIN_CLI); + BOOST_CHECK_EQUAL(GetArg("-some.tweak", "default"), "something"); +} + +BOOST_AUTO_TEST_CASE(unrecognizedArgs) +{ + BOOST_CHECK_THROW(ResetArgs("-unrecognized_arg"), std::runtime_error); + BOOST_CHECK_THROW(ResetArgs("-listen -unrecognized_arg"), std::runtime_error); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp new file mode 100644 index 00000000..540537d8 --- /dev/null +++ b/src/test/hash_tests.cpp @@ -0,0 +1,152 @@ +// Copyright (c) 2013-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "hash.h" +#include "random.h" +#include "test/test_bitcoin.h" +#include "utilstrencodings.h" + +#include + +#include + +using namespace std; + +BOOST_FIXTURE_TEST_SUITE(hash_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(murmurhash3) +{ +#define T(expected, seed, data) BOOST_CHECK_EQUAL(MurmurHash3(seed, ParseHex(data)), expected) + + // Test MurmurHash3 with various inputs. Of course this is retested in the + // bloom filter tests - they would fail if MurmurHash3() had any problems - + // but is useful for those trying to implement Bitcoin libraries as a + // source of test data for their MurmurHash3() primitive during + // development. + // + // The magic number 0xFBA4C795 comes from CBloomFilter::Hash() + + T(0x00000000, 0x00000000, ""); + T(0x6a396f08, 0xFBA4C795, ""); + T(0x81f16f39, 0xffffffff, ""); + + T(0x514e28b7, 0x00000000, "00"); + T(0xea3f0b17, 0xFBA4C795, "00"); + T(0xfd6cf10d, 0x00000000, "ff"); + + T(0x16c6b7ab, 0x00000000, "0011"); + T(0x8eb51c3d, 0x00000000, "001122"); + T(0xb4471bf8, 0x00000000, "00112233"); + T(0xe2301fa8, 0x00000000, "0011223344"); + T(0xfc2e4a15, 0x00000000, "001122334455"); + T(0xb074502c, 0x00000000, "00112233445566"); + T(0x8034d2a0, 0x00000000, "0011223344556677"); + T(0xb4698def, 0x00000000, "001122334455667788"); + +#undef T +} + +/* + SipHash-2-4 output with + k = 00 01 02 ... + and + in = (empty string) + in = 00 (1 byte) + in = 00 01 (2 bytes) + in = 00 01 02 (3 bytes) + ... + in = 00 01 02 ... 3e (63 bytes) + + from: https://131002.net/siphash/siphash24.c +*/ +uint64_t siphash_4_2_testvec[] = {0x726fdb47dd0e0e31, 0x74f839c593dc67fd, 0x0d6c8009d9a94f5a, 0x85676696d7fb7e2d, + 0xcf2794e0277187b7, 0x18765564cd99a68d, 0xcbc9466e58fee3ce, 0xab0200f58b01d137, 0x93f5f5799a932462, + 0x9e0082df0ba9e4b0, 0x7a5dbbc594ddb9f3, 0xf4b32f46226bada7, 0x751e8fbc860ee5fb, 0x14ea5627c0843d90, + 0xf723ca908e7af2ee, 0xa129ca6149be45e5, 0x3f2acc7f57c29bdb, 0x699ae9f52cbe4794, 0x4bc1b3f0968dd39c, + 0xbb6dc91da77961bd, 0xbed65cf21aa2ee98, 0xd0f2cbb02e3b67c7, 0x93536795e3a33e88, 0xa80c038ccd5ccec8, + 0xb8ad50c6f649af94, 0xbce192de8a85b8ea, 0x17d835b85bbb15f3, 0x2f2e6163076bcfad, 0xde4daaaca71dc9a5, + 0xa6a2506687956571, 0xad87a3535c49ef28, 0x32d892fad841c342, 0x7127512f72f27cce, 0xa7f32346f95978e3, + 0x12e0b01abb051238, 0x15e034d40fa197ae, 0x314dffbe0815a3b4, 0x027990f029623981, 0xcadcd4e59ef40c4d, + 0x9abfd8766a33735c, 0x0e3ea96b5304a7d0, 0xad0c42d6fc585992, 0x187306c89bc215a9, 0xd4a60abcf3792b95, + 0xf935451de4f21df2, 0xa9538f0419755787, 0xdb9acddff56ca510, 0xd06c98cd5c0975eb, 0xe612a3cb9ecba951, + 0xc766e62cfcadaf96, 0xee64435a9752fe72, 0xa192d576b245165a, 0x0a8787bf8ecb74b2, 0x81b3e73d20b49b6f, + 0x7fa8220ba3b2ecea, 0x245731c13ca42499, 0xb78dbfaf3a8d83bd, 0xea1ad565322a1a0b, 0x60e61c23a3795013, + 0x6606d7e446282b93, 0x6ca4ecb15c5f91e1, 0x9f626da15c9625f3, 0xe51b38608ef25f57, 0x958a324ceb064572}; + +BOOST_AUTO_TEST_CASE(siphash) +{ + CSipHasher hasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x726fdb47dd0e0e31ull); + static const unsigned char t0[1] = {0}; + hasher.Write(t0, 1); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x74f839c593dc67fdull); + static const unsigned char t1[7] = {1, 2, 3, 4, 5, 6, 7}; + hasher.Write(t1, 7); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x93f5f5799a932462ull); + hasher.Write(0x0F0E0D0C0B0A0908ULL); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x3f2acc7f57c29bdbull); + static const unsigned char t2[2] = {16, 17}; + hasher.Write(t2, 2); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x4bc1b3f0968dd39cull); + static const unsigned char t3[9] = {18, 19, 20, 21, 22, 23, 24, 25, 26}; + hasher.Write(t3, 9); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x2f2e6163076bcfadull); + static const unsigned char t4[5] = {27, 28, 29, 30, 31}; + hasher.Write(t4, 5); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x7127512f72f27cceull); + hasher.Write(0x2726252423222120ULL); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x0e3ea96b5304a7d0ull); + hasher.Write(0x2F2E2D2C2B2A2928ULL); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0xe612a3cb9ecba951ull); + + BOOST_CHECK_EQUAL(SipHashUint256(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL, + uint256S("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100")), + 0x7127512f72f27cceull); + + // Check test vectors from spec, one byte at a time + CSipHasher hasher2(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL); + for (uint8_t x = 0; x < ARRAYLEN(siphash_4_2_testvec); ++x) + { + BOOST_CHECK_EQUAL(hasher2.Finalize(), siphash_4_2_testvec[x]); + hasher2.Write(&x, 1); + } + // Check test vectors from spec, eight bytes at a time + CSipHasher hasher3(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL); + for (uint8_t x = 0; x < ARRAYLEN(siphash_4_2_testvec); x += 8) + { + BOOST_CHECK_EQUAL(hasher3.Finalize(), siphash_4_2_testvec[x]); + hasher3.Write(uint64_t(x) | (uint64_t(x + 1) << 8) | (uint64_t(x + 2) << 16) | (uint64_t(x + 3) << 24) | + (uint64_t(x + 4) << 32) | (uint64_t(x + 5) << 40) | (uint64_t(x + 6) << 48) | + (uint64_t(x + 7) << 56)); + } + + CHashWriter ss(SER_DISK, CLIENT_VERSION); + CMutableTransaction tx; + // Note these tests were originally written with tx.nVersion=1 + // and the test would be affected by default tx version bumps if not fixed. + tx.nVersion = 1; + ss << tx; + BOOST_CHECK_EQUAL(SipHashUint256(1, 2, ss.GetHash()), 0x79751e980c2a0a35ULL); + + // Check consistency between CSipHasher and SipHashUint256[Extra]. + FastRandomContext ctx; + for (int i = 0; i < 16; ++i) + { + uint64_t k1 = ctx.rand64(); + uint64_t k2 = ctx.rand64(); + uint256 x = GetRandHash(); + uint32_t n = ctx.rand32(); + uint8_t nb[4]; + WriteLE32(nb, n); + CSipHasher sip256(k1, k2); + sip256.Write(x.begin(), 32); + CSipHasher sip288 = sip256; + sip288.Write(nb, 4); + BOOST_CHECK_EQUAL(SipHashUint256(k1, k2, x), sip256.Finalize()); + BOOST_CHECK_EQUAL(SipHashUint256Extra(k1, k2, x, n), sip288.Finalize()); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 0a6df88f..79198bca 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -1,21 +1,30 @@ -#include - -#include -#include +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "key.h" + #include "base58.h" +#include "script/script.h" +#include "test/test_bitcoin.h" #include "uint256.h" #include "util.h" +#include "utilstrencodings.h" + +#include +#include + +#include using namespace std; -static const string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"); -static const string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"); -static const string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"); -static const string strSecret2C ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g"); -static const CBitcoinAddress addr1 ("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ"); -static const CBitcoinAddress addr2 ("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ"); +static const string strSecret1("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"); +static const string strSecret2("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"); +static const string strSecret1C("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"); +static const string strSecret2C("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g"); +static const CBitcoinAddress addr1("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ"); +static const CBitcoinAddress addr2("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ"); static const CBitcoinAddress addr1C("1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs"); static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"); @@ -26,15 +35,15 @@ static const string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"); #ifdef KEY_TESTS_DUMPINFO void dumpKeyInfo(uint256 privkey) { - CSecret secret; - secret.resize(32); + CKey key; + key.resize(32); memcpy(&secret[0], &privkey, 32); vector sec; sec.resize(32); memcpy(&sec[0], &secret[0], 32); printf(" * secret (hex): %s\n", HexStr(sec).c_str()); - for (int nCompressed=0; nCompressed<2; nCompressed++) + for (int nCompressed = 0; nCompressed < 2; nCompressed++) { bool fCompressed = nCompressed == 1; printf(" * %s:\n", fCompressed ? "compressed" : "uncompressed"); @@ -51,42 +60,57 @@ void dumpKeyInfo(uint256 privkey) #endif -BOOST_AUTO_TEST_SUITE(key_tests) +BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(key_test1) { CBitcoinSecret bsecret1, bsecret2, bsecret1C, bsecret2C, baddress1; - BOOST_CHECK( bsecret1.SetString (strSecret1)); - BOOST_CHECK( bsecret2.SetString (strSecret2)); - BOOST_CHECK( bsecret1C.SetString(strSecret1C)); - BOOST_CHECK( bsecret2C.SetString(strSecret2C)); + BOOST_CHECK(bsecret1.SetString(strSecret1)); + BOOST_CHECK(bsecret2.SetString(strSecret2)); + BOOST_CHECK(bsecret1C.SetString(strSecret1C)); + BOOST_CHECK(bsecret2C.SetString(strSecret2C)); BOOST_CHECK(!baddress1.SetString(strAddressBad)); - bool fCompressed; - CSecret secret1 = bsecret1.GetSecret (fCompressed); - BOOST_CHECK(fCompressed == false); - CSecret secret2 = bsecret2.GetSecret (fCompressed); - BOOST_CHECK(fCompressed == false); - CSecret secret1C = bsecret1C.GetSecret(fCompressed); - BOOST_CHECK(fCompressed == true); - CSecret secret2C = bsecret2C.GetSecret(fCompressed); - BOOST_CHECK(fCompressed == true); - - BOOST_CHECK(secret1 == secret1C); - BOOST_CHECK(secret2 == secret2C); - - CKey key1, key2, key1C, key2C; - key1.SetSecret(secret1, false); - key2.SetSecret(secret2, false); - key1C.SetSecret(secret1, true); - key2C.SetSecret(secret2, true); - - BOOST_CHECK(addr1.Get() == CTxDestination(key1.GetPubKey().GetID())); - BOOST_CHECK(addr2.Get() == CTxDestination(key2.GetPubKey().GetID())); - BOOST_CHECK(addr1C.Get() == CTxDestination(key1C.GetPubKey().GetID())); - BOOST_CHECK(addr2C.Get() == CTxDestination(key2C.GetPubKey().GetID())); - - for (int n=0; n<16; n++) + CKey key1 = bsecret1.GetKey(); + BOOST_CHECK(key1.IsCompressed() == false); + CKey key2 = bsecret2.GetKey(); + BOOST_CHECK(key2.IsCompressed() == false); + CKey key1C = bsecret1C.GetKey(); + BOOST_CHECK(key1C.IsCompressed() == true); + CKey key2C = bsecret2C.GetKey(); + BOOST_CHECK(key2C.IsCompressed() == true); + + CPubKey pubkey1 = key1.GetPubKey(); + CPubKey pubkey2 = key2.GetPubKey(); + CPubKey pubkey1C = key1C.GetPubKey(); + CPubKey pubkey2C = key2C.GetPubKey(); + + BOOST_CHECK(key1.VerifyPubKey(pubkey1)); + BOOST_CHECK(!key1.VerifyPubKey(pubkey1C)); + BOOST_CHECK(!key1.VerifyPubKey(pubkey2)); + BOOST_CHECK(!key1.VerifyPubKey(pubkey2C)); + + BOOST_CHECK(!key1C.VerifyPubKey(pubkey1)); + BOOST_CHECK(key1C.VerifyPubKey(pubkey1C)); + BOOST_CHECK(!key1C.VerifyPubKey(pubkey2)); + BOOST_CHECK(!key1C.VerifyPubKey(pubkey2C)); + + BOOST_CHECK(!key2.VerifyPubKey(pubkey1)); + BOOST_CHECK(!key2.VerifyPubKey(pubkey1C)); + BOOST_CHECK(key2.VerifyPubKey(pubkey2)); + BOOST_CHECK(!key2.VerifyPubKey(pubkey2C)); + + BOOST_CHECK(!key2C.VerifyPubKey(pubkey1)); + BOOST_CHECK(!key2C.VerifyPubKey(pubkey1C)); + BOOST_CHECK(!key2C.VerifyPubKey(pubkey2)); + BOOST_CHECK(key2C.VerifyPubKey(pubkey2C)); + + BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID())); + BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID())); + BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID())); + BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID())); + + for (int n = 0; n < 16; n++) { string strMsg = strprintf("Very secret message %i: 11", n); uint256 hashMsg = Hash(strMsg.begin(), strMsg.end()); @@ -95,53 +119,80 @@ BOOST_AUTO_TEST_CASE(key_test1) vector sign1, sign2, sign1C, sign2C; - BOOST_CHECK(key1.Sign (hashMsg, sign1)); - BOOST_CHECK(key2.Sign (hashMsg, sign2)); + BOOST_CHECK(key1.Sign(hashMsg, sign1)); + BOOST_CHECK(key2.Sign(hashMsg, sign2)); BOOST_CHECK(key1C.Sign(hashMsg, sign1C)); BOOST_CHECK(key2C.Sign(hashMsg, sign2C)); - BOOST_CHECK( key1.Verify(hashMsg, sign1)); - BOOST_CHECK(!key1.Verify(hashMsg, sign2)); - BOOST_CHECK( key1.Verify(hashMsg, sign1C)); - BOOST_CHECK(!key1.Verify(hashMsg, sign2C)); + BOOST_CHECK(pubkey1.Verify(hashMsg, sign1)); + BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2)); + BOOST_CHECK(pubkey1.Verify(hashMsg, sign1C)); + BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C)); - BOOST_CHECK(!key2.Verify(hashMsg, sign1)); - BOOST_CHECK( key2.Verify(hashMsg, sign2)); - BOOST_CHECK(!key2.Verify(hashMsg, sign1C)); - BOOST_CHECK( key2.Verify(hashMsg, sign2C)); + BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1)); + BOOST_CHECK(pubkey2.Verify(hashMsg, sign2)); + BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C)); + BOOST_CHECK(pubkey2.Verify(hashMsg, sign2C)); - BOOST_CHECK( key1C.Verify(hashMsg, sign1)); - BOOST_CHECK(!key1C.Verify(hashMsg, sign2)); - BOOST_CHECK( key1C.Verify(hashMsg, sign1C)); - BOOST_CHECK(!key1C.Verify(hashMsg, sign2C)); + BOOST_CHECK(pubkey1C.Verify(hashMsg, sign1)); + BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2)); + BOOST_CHECK(pubkey1C.Verify(hashMsg, sign1C)); + BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C)); - BOOST_CHECK(!key2C.Verify(hashMsg, sign1)); - BOOST_CHECK( key2C.Verify(hashMsg, sign2)); - BOOST_CHECK(!key2C.Verify(hashMsg, sign1C)); - BOOST_CHECK( key2C.Verify(hashMsg, sign2C)); + BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1)); + BOOST_CHECK(pubkey2C.Verify(hashMsg, sign2)); + BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C)); + BOOST_CHECK(pubkey2C.Verify(hashMsg, sign2C)); // compact signatures (with key recovery) vector csign1, csign2, csign1C, csign2C; - BOOST_CHECK(key1.SignCompact (hashMsg, csign1)); - BOOST_CHECK(key2.SignCompact (hashMsg, csign2)); + BOOST_CHECK(key1.SignCompact(hashMsg, csign1)); + BOOST_CHECK(key2.SignCompact(hashMsg, csign2)); BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C)); BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C)); - CKey rkey1, rkey2, rkey1C, rkey2C; - - BOOST_CHECK(rkey1.SetCompactSignature (hashMsg, csign1)); - BOOST_CHECK(rkey2.SetCompactSignature (hashMsg, csign2)); - BOOST_CHECK(rkey1C.SetCompactSignature(hashMsg, csign1C)); - BOOST_CHECK(rkey2C.SetCompactSignature(hashMsg, csign2C)); + CPubKey rkey1, rkey2, rkey1C, rkey2C; + BOOST_CHECK(rkey1.RecoverCompact(hashMsg, csign1)); + BOOST_CHECK(rkey2.RecoverCompact(hashMsg, csign2)); + BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C)); + BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C)); - BOOST_CHECK(rkey1.GetPubKey() == key1.GetPubKey()); - BOOST_CHECK(rkey2.GetPubKey() == key2.GetPubKey()); - BOOST_CHECK(rkey1C.GetPubKey() == key1C.GetPubKey()); - BOOST_CHECK(rkey2C.GetPubKey() == key2C.GetPubKey()); + BOOST_CHECK(rkey1 == pubkey1); + BOOST_CHECK(rkey2 == pubkey2); + BOOST_CHECK(rkey1C == pubkey1C); + BOOST_CHECK(rkey2C == pubkey2C); } + + // test deterministic signing + + std::vector detsig, detsigc; + string strMsg = "Very deterministic message"; + uint256 hashMsg = Hash(strMsg.begin(), strMsg.end()); + BOOST_CHECK(key1.Sign(hashMsg, detsig)); + BOOST_CHECK(key1C.Sign(hashMsg, detsigc)); + BOOST_CHECK(detsig == detsigc); + BOOST_CHECK(detsig == ParseHex("304402205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d022014ddda2" + "1494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6")); + BOOST_CHECK(key2.Sign(hashMsg, detsig)); + BOOST_CHECK(key2C.Sign(hashMsg, detsigc)); + BOOST_CHECK(detsig == detsigc); + BOOST_CHECK(detsig == ParseHex("3044022052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd5022061d8ae5" + "e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); + BOOST_CHECK(key1.SignCompact(hashMsg, detsig)); + BOOST_CHECK(key1C.SignCompact(hashMsg, detsigc)); + BOOST_CHECK(detsig == ParseHex("1c5dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221" + "f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6")); + BOOST_CHECK(detsigc == ParseHex("205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e22" + "1f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6")); + BOOST_CHECK(key2.SignCompact(hashMsg, detsig)); + BOOST_CHECK(key2C.SignCompact(hashMsg, detsigc)); + BOOST_CHECK(detsig == ParseHex("1c52d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16b" + "de3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); + BOOST_CHECK(detsigc == ParseHex("2052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16" + "bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/limitedmap_tests.cpp b/src/test/limitedmap_tests.cpp new file mode 100644 index 00000000..0fc0e4b3 --- /dev/null +++ b/src/test/limitedmap_tests.cpp @@ -0,0 +1,110 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "limitedmap.h" + +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(limitedmap_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(limitedmap_test) +{ + // create a limitedmap capped at 10 items + limitedmap map(10); + + // check that the max size is 10 + BOOST_CHECK(map.max_size() == 10); + + // check that it's empty + BOOST_CHECK(map.size() == 0); + + // insert (-1, -1) + map.insert(std::pair(-1, -1)); + + // make sure that the size is updated + BOOST_CHECK(map.size() == 1); + + // make sure that the new items is in the map + BOOST_CHECK(map.count(-1) == 1); + + // insert 10 new items + for (int i = 0; i < 10; i++) + { + map.insert(std::pair(i, i + 1)); + } + + // make sure that the map now contains 10 items... + BOOST_CHECK(map.size() == 10); + + // ...and that the first item has been discarded + BOOST_CHECK(map.count(-1) == 0); + + // iterate over the map, both with an index and an iterator + limitedmap::const_iterator it = map.begin(); + for (int i = 0; i < 10; i++) + { + // make sure the item is present + BOOST_CHECK(map.count(i) == 1); + + // use the iterator to check for the expected key adn value + BOOST_CHECK(it->first == i); + BOOST_CHECK(it->second == i + 1); + + // use find to check for the value + BOOST_CHECK(map.find(i)->second == i + 1); + + // update and recheck + map.update(it, i + 2); + BOOST_CHECK(map.find(i)->second == i + 2); + + it++; + } + + // check that we've exhausted the iterator + BOOST_CHECK(it == map.end()); + + // resize the map to 5 items + map.max_size(5); + + // check that the max size and size are now 5 + BOOST_CHECK(map.max_size() == 5); + BOOST_CHECK(map.size() == 5); + + // check that items less than 5 have been discarded + // and items greater than 5 are retained + for (int i = 0; i < 10; i++) + { + if (i < 5) + { + BOOST_CHECK(map.count(i) == 0); + } + else + { + BOOST_CHECK(map.count(i) == 1); + } + } + + // erase some items not in the map + for (int i = 100; i < 1000; i += 100) + { + map.erase(i); + } + + // check that the size is unaffected + BOOST_CHECK(map.size() == 5); + + // erase the remaining elements + for (int i = 5; i < 10; i++) + { + map.erase(i); + } + + // check that the map is now empty + BOOST_CHECK(map.empty()); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp new file mode 100644 index 00000000..c220278a --- /dev/null +++ b/src/test/main_tests.cpp @@ -0,0 +1,77 @@ +// Copyright (c) 2014-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "main.h" +#include "chainparams.h" + +#include "test/test_bitcoin.h" + +#include +#include + +BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup) + +static void TestBlockSubsidyHalvings(const Consensus::Params &consensusParams) +{ + int maxHalvings = 64; + CAmount nInitialSubsidy = 50 * COIN; + + CAmount nPreviousSubsidy = nInitialSubsidy * 2; // for height == 0 + BOOST_CHECK_EQUAL(nPreviousSubsidy, nInitialSubsidy * 2); + for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) + { + int nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval; + CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams); + BOOST_CHECK(nSubsidy <= nInitialSubsidy); + BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2); + nPreviousSubsidy = nSubsidy; + } + BOOST_CHECK_EQUAL(GetBlockSubsidy(maxHalvings * consensusParams.nSubsidyHalvingInterval, consensusParams), 0); +} + +static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval) +{ + Consensus::Params consensusParams; + consensusParams.nSubsidyHalvingInterval = nSubsidyHalvingInterval; + TestBlockSubsidyHalvings(consensusParams); +} + +BOOST_AUTO_TEST_CASE(block_subsidy_test) +{ + TestBlockSubsidyHalvings(Params(CBaseChainParams::MAIN).GetConsensus()); // As in main + TestBlockSubsidyHalvings(150); // As in regtest + TestBlockSubsidyHalvings(1000); // Just another interval +} + +BOOST_AUTO_TEST_CASE(subsidy_limit_test) +{ + const Consensus::Params &consensusParams = Params(CBaseChainParams::MAIN).GetConsensus(); + CAmount nSum = 0; + for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) + { + CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams); + BOOST_CHECK(nSubsidy <= 50 * COIN); + nSum += nSubsidy * 1000; + BOOST_CHECK(MoneyRange(nSum)); + } + BOOST_CHECK_EQUAL(nSum, 2099999997690000ULL); +} + +bool ReturnFalse() { return false; } +bool ReturnTrue() { return true; } +BOOST_AUTO_TEST_CASE(test_combiner_all) +{ + boost::signals2::signal Test; + BOOST_CHECK(Test()); + Test.connect(&ReturnFalse); + BOOST_CHECK(!Test()); + Test.connect(&ReturnTrue); + BOOST_CHECK(!Test()); + Test.disconnect(&ReturnFalse); + BOOST_CHECK(Test()); + Test.disconnect(&ReturnTrue); + BOOST_CHECK(Test()); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp new file mode 100644 index 00000000..d7284f69 --- /dev/null +++ b/src/test/mempool_tests.cpp @@ -0,0 +1,496 @@ +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "txmempool.h" +#include "util.h" + +#include "test/test_bitcoin.h" + +#include +#include +#include + +BOOST_FIXTURE_TEST_SUITE(mempool_tests, TestingSetup) + +BOOST_AUTO_TEST_CASE(MempoolRemoveTest) +{ + // Test CTxMemPool::remove functionality + + TestMemPoolEntryHelper entry; + // Parent transaction with three children, + // and three grand-children: + CMutableTransaction txParent; + txParent.vin.resize(1); + txParent.vin[0].scriptSig = CScript() << OP_11; + txParent.vout.resize(3); + for (int i = 0; i < 3; i++) + { + txParent.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + txParent.vout[i].nValue = 33000LL; + } + CMutableTransaction txChild[3]; + for (int i = 0; i < 3; i++) + { + txChild[i].vin.resize(1); + txChild[i].vin[0].scriptSig = CScript() << OP_11; + txChild[i].vin[0].prevout.hash = txParent.GetHash(); + txChild[i].vin[0].prevout.n = i; + txChild[i].vout.resize(1); + txChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + txChild[i].vout[0].nValue = 11000LL; + } + CMutableTransaction txGrandChild[3]; + for (int i = 0; i < 3; i++) + { + txGrandChild[i].vin.resize(1); + txGrandChild[i].vin[0].scriptSig = CScript() << OP_11; + txGrandChild[i].vin[0].prevout.hash = txChild[i].GetHash(); + txGrandChild[i].vin[0].prevout.n = 0; + txGrandChild[i].vout.resize(1); + txGrandChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + txGrandChild[i].vout[0].nValue = 11000LL; + } + + + CTxMemPool testPool(CFeeRate(0)); + std::list removed; + + // Nothing in pool, remove should do nothing: + testPool.remove(txParent, removed, true); + BOOST_CHECK_EQUAL(removed.size(), 0); + + // Just the parent: + testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); + testPool.remove(txParent, removed, true); + BOOST_CHECK_EQUAL(removed.size(), 1); + removed.clear(); + + // Parent, children, grandchildren: + testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); + for (int i = 0; i < 3; i++) + { + testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i])); + testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); + } + // Remove Child[0], GrandChild[0] should be removed: + testPool.remove(txChild[0], removed, true); + BOOST_CHECK_EQUAL(removed.size(), 2); + removed.clear(); + // ... make sure grandchild and child are gone: + testPool.remove(txGrandChild[0], removed, true); + BOOST_CHECK_EQUAL(removed.size(), 0); + testPool.remove(txChild[0], removed, true); + BOOST_CHECK_EQUAL(removed.size(), 0); + // Remove parent, all children/grandchildren should go: + testPool.remove(txParent, removed, true); + BOOST_CHECK_EQUAL(removed.size(), 5); + BOOST_CHECK_EQUAL(testPool.size(), 0); + removed.clear(); + + // Add children and grandchildren, but NOT the parent (simulate the parent being in a block) + for (int i = 0; i < 3; i++) + { + testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i])); + testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); + } + // 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); + BOOST_CHECK_EQUAL(removed.size(), 6); + BOOST_CHECK_EQUAL(testPool.size(), 0); + removed.clear(); +} + +template +void CheckSort(CTxMemPool &pool, std::vector &sortedOrder) +{ + BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size()); + typename CTxMemPool::indexed_transaction_set::index::type::iterator it = pool.mapTx.get().begin(); + int count = 0; + for (; it != pool.mapTx.get().end(); ++it, ++count) + { + BOOST_CHECK_EQUAL(it->GetTx().GetHash().ToString(), sortedOrder[count]); + } +} + +BOOST_AUTO_TEST_CASE(MempoolIndexingTest) +{ + 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)); + + /* 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; + entry.nTime = 1; + entry.dPriority = 10.0; + pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); + BOOST_CHECK_EQUAL(pool.size(), 5); + + std::vector sortedOrder; + sortedOrder.resize(5); + sortedOrder[0] = tx3.GetHash().ToString(); // 0 + sortedOrder[1] = tx5.GetHash().ToString(); // 10000 + sortedOrder[2] = tx1.GetHash().ToString(); // 10000 + sortedOrder[3] = tx4.GetHash().ToString(); // 15000 + sortedOrder[4] = tx2.GetHash().ToString(); // 20000 + CheckSort(pool, sortedOrder); + + /* low fee but with high fee child */ + /* tx6 -> tx7 -> tx8, tx9 -> tx10 */ + CMutableTransaction tx6 = CMutableTransaction(); + tx6.vout.resize(1); + tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx6.vout[0].nValue = 20 * COIN; + pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6)); + BOOST_CHECK_EQUAL(pool.size(), 6); + // Check that at this point, tx6 is sorted low + sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString()); + CheckSort(pool, sortedOrder); + + CTxMemPool::setEntries setAncestors; + setAncestors.insert(pool.mapTx.find(tx6.GetHash())); + 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(2); + tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx7.vout[0].nValue = 10 * COIN; + tx7.vout[1].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx7.vout[1].nValue = 1 * COIN; + + CTxMemPool::setEntries setAncestorsCalculated; + std::string dummy; + BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors( + entry.Fee(2000000LL).FromTx(tx7), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), + true); + BOOST_CHECK(setAncestorsCalculated == setAncestors); + + pool.addUnchecked(tx7.GetHash(), entry.FromTx(tx7), setAncestors); + BOOST_CHECK_EQUAL(pool.size(), 7); + + // Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ... + sortedOrder.erase(sortedOrder.begin()); + sortedOrder.push_back(tx6.GetHash().ToString()); + sortedOrder.push_back(tx7.GetHash().ToString()); + CheckSort(pool, sortedOrder); + + /* low fee child of tx7 */ + CMutableTransaction tx8 = CMutableTransaction(); + tx8.vin.resize(1); + tx8.vin[0].prevout = COutPoint(tx7.GetHash(), 0); + tx8.vin[0].scriptSig = CScript() << OP_11; + tx8.vout.resize(1); + tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx8.vout[0].nValue = 10 * COIN; + setAncestors.insert(pool.mapTx.find(tx7.GetHash())); + pool.addUnchecked(tx8.GetHash(), entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors); + + // Now tx8 should be sorted low, but tx6/tx both high + sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString()); + CheckSort(pool, sortedOrder); + + /* low fee child of tx7 */ + CMutableTransaction tx9 = CMutableTransaction(); + tx9.vin.resize(1); + tx9.vin[0].prevout = COutPoint(tx7.GetHash(), 1); + tx9.vin[0].scriptSig = CScript() << OP_11; + tx9.vout.resize(1); + tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx9.vout[0].nValue = 1 * COIN; + pool.addUnchecked(tx9.GetHash(), entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors); + + // tx9 should be sorted low + BOOST_CHECK_EQUAL(pool.size(), 9); + sortedOrder.insert(sortedOrder.begin(), tx9.GetHash().ToString()); + CheckSort(pool, sortedOrder); + + std::vector snapshotOrder = sortedOrder; + + setAncestors.insert(pool.mapTx.find(tx8.GetHash())); + setAncestors.insert(pool.mapTx.find(tx9.GetHash())); + /* tx10 depends on tx8 and tx9 and has a high fee*/ + CMutableTransaction tx10 = CMutableTransaction(); + tx10.vin.resize(2); + tx10.vin[0].prevout = COutPoint(tx8.GetHash(), 0); + tx10.vin[0].scriptSig = CScript() << OP_11; + tx10.vin[1].prevout = COutPoint(tx9.GetHash(), 0); + tx10.vin[1].scriptSig = CScript() << OP_11; + tx10.vout.resize(1); + tx10.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx10.vout[0].nValue = 10 * COIN; + + setAncestorsCalculated.clear(); + BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(4).FromTx(tx10), setAncestorsCalculated, + 100, 1000000, 1000, 1000000, dummy), + true); + BOOST_CHECK(setAncestorsCalculated == setAncestors); + + pool.addUnchecked(tx10.GetHash(), entry.FromTx(tx10), setAncestors); + + /** + * tx8 and tx9 should both now be sorted higher + * Final order after tx10 is added: + * + * tx3 = 0 (1) + * tx5 = 10000 (1) + * tx1 = 10000 (1) + * tx4 = 15000 (1) + * tx2 = 20000 (1) + * tx9 = 200k (2 txs) + * tx8 = 200k (2 txs) + * tx10 = 200k (1 tx) + * tx6 = 2.2M (5 txs) + * tx7 = 2.2M (4 txs) + */ + sortedOrder.erase(sortedOrder.begin(), sortedOrder.begin() + 2); // take out tx9, tx8 from the beginning + 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(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 removed; + pool.remove(pool.mapTx.find(tx10.GetHash())->GetTx(), removed, true); + CheckSort(pool, snapshotOrder); + + pool.remove(pool.mapTx.find(tx9.GetHash())->GetTx(), removed, true); + pool.remove(pool.mapTx.find(tx8.GetHash())->GetTx(), removed, true); + /* Now check the sort on the mining score index. + * Final order should be: + * + * tx7 (2M) + * tx2 (20k) + * tx4 (15000) + * tx1/tx5 (10000) + * tx3/6 (0) + * (Ties resolved by hash) + */ + sortedOrder.clear(); + sortedOrder.push_back(tx7.GetHash().ToString()); + sortedOrder.push_back(tx2.GetHash().ToString()); + sortedOrder.push_back(tx4.GetHash().ToString()); + if (tx1.GetHash() < tx5.GetHash()) + { + sortedOrder.push_back(tx5.GetHash().ToString()); + sortedOrder.push_back(tx1.GetHash().ToString()); + } + else + { + sortedOrder.push_back(tx1.GetHash().ToString()); + sortedOrder.push_back(tx5.GetHash().ToString()); + } + if (tx3.GetHash() < tx6.GetHash()) + { + sortedOrder.push_back(tx6.GetHash().ToString()); + sortedOrder.push_back(tx3.GetHash().ToString()); + } + else + { + sortedOrder.push_back(tx3.GetHash().ToString()); + sortedOrder.push_back(tx6.GetHash().ToString()); + } + CheckSort(pool, sortedOrder); +} + + +BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) +{ + CTxMemPool pool(CFeeRate(1000)); + TestMemPoolEntryHelper entry; + entry.dPriority = 10.0; + + CMutableTransaction tx1 = CMutableTransaction(); + tx1.vin.resize(1); + tx1.vin[0].scriptSig = CScript() << OP_1; + tx1.vout.resize(1); + tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL; + tx1.vout[0].nValue = 10 * COIN; + pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1, &pool)); + + CMutableTransaction tx2 = CMutableTransaction(); + tx2.vin.resize(1); + tx2.vin[0].scriptSig = CScript() << OP_2; + tx2.vout.resize(1); + tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL; + tx2.vout[0].nValue = 10 * COIN; + pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2, &pool)); + + pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing + BOOST_CHECK(pool.exists(tx1.GetHash())); + BOOST_CHECK(pool.exists(tx2.GetHash())); + + pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction + BOOST_CHECK(pool.exists(tx1.GetHash())); + BOOST_CHECK(!pool.exists(tx2.GetHash())); + + pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2, &pool)); + CMutableTransaction tx3 = CMutableTransaction(); + tx3.vin.resize(1); + tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0); + tx3.vin[0].scriptSig = CScript() << OP_2; + tx3.vout.resize(1); + tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL; + tx3.vout[0].nValue = 10 * COIN; + pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3, &pool)); + + pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP) + BOOST_CHECK(!pool.exists(tx1.GetHash())); + BOOST_CHECK(pool.exists(tx2.GetHash())); + BOOST_CHECK(pool.exists(tx3.GetHash())); + + // mempool is limited to tx1's size in memory usage, so nothing fits + pool.TrimToSize(::GetSerializeSize(CTransaction(tx1), SER_NETWORK, PROTOCOL_VERSION)); + BOOST_CHECK(!pool.exists(tx1.GetHash())); + BOOST_CHECK(!pool.exists(tx2.GetHash())); + BOOST_CHECK(!pool.exists(tx3.GetHash())); + + CFeeRate maxFeeRateRemoved(25000, ::GetSerializeSize(CTransaction(tx3), SER_NETWORK, PROTOCOL_VERSION) + + ::GetSerializeSize(CTransaction(tx2), SER_NETWORK, PROTOCOL_VERSION)); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000); + + CMutableTransaction tx4 = CMutableTransaction(); + tx4.vin.resize(2); + tx4.vin[0].prevout.SetNull(); + tx4.vin[0].scriptSig = CScript() << OP_4; + tx4.vin[1].prevout.SetNull(); + tx4.vin[1].scriptSig = CScript() << OP_4; + tx4.vout.resize(2); + tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL; + tx4.vout[0].nValue = 10 * COIN; + tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL; + tx4.vout[1].nValue = 10 * COIN; + + CMutableTransaction tx5 = CMutableTransaction(); + tx5.vin.resize(2); + tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0); + tx5.vin[0].scriptSig = CScript() << OP_4; + tx5.vin[1].prevout.SetNull(); + tx5.vin[1].scriptSig = CScript() << OP_5; + tx5.vout.resize(2); + tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL; + tx5.vout[0].nValue = 10 * COIN; + tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL; + tx5.vout[1].nValue = 10 * COIN; + + CMutableTransaction tx6 = CMutableTransaction(); + tx6.vin.resize(2); + tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1); + tx6.vin[0].scriptSig = CScript() << OP_4; + tx6.vin[1].prevout.SetNull(); + tx6.vin[1].scriptSig = CScript() << OP_6; + tx6.vout.resize(2); + tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL; + tx6.vout[0].nValue = 10 * COIN; + tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL; + tx6.vout[1].nValue = 10 * COIN; + + CMutableTransaction tx7 = CMutableTransaction(); + tx7.vin.resize(2); + tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0); + tx7.vin[0].scriptSig = CScript() << OP_5; + tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0); + tx7.vin[1].scriptSig = CScript() << OP_6; + tx7.vout.resize(2); + tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL; + tx7.vout[0].nValue = 10 * COIN; + tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL; + tx7.vout[1].nValue = 10 * COIN; + + pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4, &pool)); + pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); + pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6, &pool)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); + + // we only require this remove, at max, 2 txn, because its not clear what we're really optimizing for aside from + // that + pool.TrimToSize(pool.DynamicMemoryUsage() - 1); + BOOST_CHECK(pool.exists(tx4.GetHash())); + BOOST_CHECK(pool.exists(tx6.GetHash())); + BOOST_CHECK(!pool.exists(tx7.GetHash())); + + if (!pool.exists(tx5.GetHash())) + pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); + + pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7 + BOOST_CHECK(pool.exists(tx4.GetHash())); + BOOST_CHECK(!pool.exists(tx5.GetHash())); + BOOST_CHECK(pool.exists(tx6.GetHash())); + BOOST_CHECK(!pool.exists(tx7.GetHash())); + + pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); + + std::vector vtx; + std::list conflicts; + SetMockTime(42); + SetMockTime(42 + CTxMemPool::ROLLING_FEE_HALFLIFE); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000); + // ... we should keep the same min fee until we get a block + pool.removeForBlock(vtx, 1, conflicts); + SetMockTime(42 + 2 * CTxMemPool::ROLLING_FEE_HALFLIFE); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000) / 2); + // ... then feerate should drop 1/2 each halflife + + SetMockTime(42 + 2 * CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE / 2); + BOOST_CHECK_EQUAL( + pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000) / 4); + // ... with a 1/2 halflife when mempool is < 1/2 its target size + + SetMockTime(42 + 2 * CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE / 2 + + CTxMemPool::ROLLING_FEE_HALFLIFE / 4); + BOOST_CHECK_EQUAL( + pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000) / 8); + // ... with a 1/4 halflife when mempool is < 1/4 its target size + + SetMockTime(42 + 7 * CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE / 2 + + CTxMemPool::ROLLING_FEE_HALFLIFE / 4); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 1000); + // ... but feerate should never drop below 1000 + + SetMockTime(42 + 8 * CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE / 2 + + CTxMemPool::ROLLING_FEE_HALFLIFE / 4); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0); + // ... unless it has gone all the way to 0 (after getting past 1000/2) + + SetMockTime(0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp new file mode 100644 index 00000000..994ad3a8 --- /dev/null +++ b/src/test/merkle_tests.cpp @@ -0,0 +1,157 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "consensus/merkle.h" +#include "random.h" +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(merkle_tests, TestingSetup) + +// Older version of the merkle root computation code, for comparison. +static uint256 BlockBuildMerkleTree(const CBlock &block, bool *fMutated, std::vector &vMerkleTree) +{ + vMerkleTree.clear(); + vMerkleTree.reserve(block.vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes. + for (std::vector::const_iterator it(block.vtx.begin()); it != block.vtx.end(); ++it) + vMerkleTree.push_back(it->GetHash()); + int j = 0; + bool mutated = false; + for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + for (int i = 0; i < nSize; i += 2) + { + int i2 = std::min(i + 1, nSize - 1); + if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j + i] == vMerkleTree[j + i2]) + { + // Two identical hashes at the end of the list at a particular level. + mutated = true; + } + vMerkleTree.push_back(Hash(vMerkleTree[j + i].begin(), vMerkleTree[j + i].end(), + vMerkleTree[j + i2].begin(), vMerkleTree[j + i2].end())); + } + j += nSize; + } + if (fMutated) + { + *fMutated = mutated; + } + return (vMerkleTree.empty() ? uint256() : vMerkleTree.back()); +} + +// Older version of the merkle branch computation code, for comparison. +static std::vector BlockGetMerkleBranch(const CBlock &block, + const std::vector &vMerkleTree, + int nIndex) +{ + std::vector vMerkleBranch; + int j = 0; + for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + int i = std::min(nIndex ^ 1, nSize - 1); + vMerkleBranch.push_back(vMerkleTree[j + i]); + nIndex >>= 1; + j += nSize; + } + return vMerkleBranch; +} + +static inline int ctz(uint32_t i) +{ + if (i == 0) + return 0; + int j = 0; + while (!(i & 1)) + { + j++; + i >>= 1; + } + return j; +} + +BOOST_AUTO_TEST_CASE(merkle_test) +{ + for (int i = 0; i < 32; i++) + { + // Try 32 block sizes: all sizes from 0 to 16 inclusive, and then 15 random sizes. + int ntx = (i <= 16) ? i : 17 + (insecure_rand() % 4000); + // Try up to 3 mutations. + for (int mutate = 0; mutate <= 3; mutate++) + { + int duplicate1 = mutate >= 1 ? 1 << ctz(ntx) : 0; // The last how many transactions to duplicate first. + // Duplication of the entire tree results in a different root (it adds a level). + if (duplicate1 >= ntx) + break; + int ntx1 = ntx + duplicate1; // The resulting number of transactions after the first duplication. + int duplicate2 = mutate >= 2 ? 1 << ctz(ntx1) : 0; // Likewise for the second mutation. + if (duplicate2 >= ntx1) + break; + int ntx2 = ntx1 + duplicate2; + int duplicate3 = mutate >= 3 ? 1 << ctz(ntx2) : 0; // And for the third mutation. + if (duplicate3 >= ntx2) + break; + int ntx3 = ntx2 + duplicate3; + // Build a block with ntx different transactions. + CBlock block; + block.vtx.resize(ntx); + for (int j = 0; j < ntx; j++) + { + CMutableTransaction mtx; + mtx.nLockTime = j; + block.vtx[j] = mtx; + } + // Compute the root of the block before mutating it. + bool unmutatedMutated = false; + uint256 unmutatedRoot = BlockMerkleRoot(block, &unmutatedMutated); + BOOST_CHECK(unmutatedMutated == false); + // Optionally mutate by duplicating the last transactions, resulting in the same merkle root. + block.vtx.resize(ntx3); + for (int j = 0; j < duplicate1; j++) + { + block.vtx[ntx + j] = block.vtx[ntx + j - duplicate1]; + } + for (int j = 0; j < duplicate2; j++) + { + block.vtx[ntx1 + j] = block.vtx[ntx1 + j - duplicate2]; + } + for (int j = 0; j < duplicate3; j++) + { + block.vtx[ntx2 + j] = block.vtx[ntx2 + j - duplicate3]; + } + // Compute the merkle root and merkle tree using the old mechanism. + bool oldMutated = false; + std::vector merkleTree; + uint256 oldRoot = BlockBuildMerkleTree(block, &oldMutated, merkleTree); + // Compute the merkle root using the new mechanism. + bool newMutated = false; + uint256 newRoot = BlockMerkleRoot(block, &newMutated); + BOOST_CHECK(oldRoot == newRoot); + BOOST_CHECK(newRoot == unmutatedRoot); + BOOST_CHECK((newRoot == uint256()) == (ntx == 0)); + BOOST_CHECK(oldMutated == newMutated); + BOOST_CHECK(newMutated == !!mutate); + // If no mutation was done (once for every ntx value), try up to 16 branches. + if (mutate == 0) + { + for (int loop = 0; loop < std::min(ntx, 16); loop++) + { + // If ntx <= 16, try all branches. Otherise, try 16 random ones. + int mtx = loop; + if (ntx > 16) + { + mtx = insecure_rand() % ntx; + } + std::vector newBranch = BlockMerkleBranch(block, mtx); + std::vector oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx); + BOOST_CHECK(oldBranch == newBranch); + BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx].GetHash(), newBranch, mtx) == oldRoot); + } + } + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 4558a76a..915f193f 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -1,84 +1,136 @@ -#include +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "init.h" +#include "miner.h" +#include "chainparams.h" +#include "coins.h" +#include "consensus/consensus.h" +#include "consensus/merkle.h" +#include "consensus/validation.h" #include "main.h" +#include "pubkey.h" +#include "script/standard.h" +#include "txmempool.h" #include "uint256.h" #include "util.h" -#include "wallet.h" +#include "utilstrencodings.h" + +#include "test/test_bitcoin.h" -extern void SHA256Transform(void* pstate, void* pinput, const void* pinit); +#include -BOOST_AUTO_TEST_SUITE(miner_tests) +BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup) -static -struct { +static struct +{ unsigned char extranonce; unsigned int nonce; } blockinfo[] = { - {4, 0xa4a3e223}, {2, 0x15c32f9e}, {1, 0x0375b547}, {1, 0x7004a8a5}, - {2, 0xce440296}, {2, 0x52cfe198}, {1, 0x77a72cd0}, {2, 0xbb5d6f84}, - {2, 0x83f30c2c}, {1, 0x48a73d5b}, {1, 0xef7dcd01}, {2, 0x6809c6c4}, - {2, 0x0883ab3c}, {1, 0x087bbbe2}, {2, 0x2104a814}, {2, 0xdffb6daa}, - {1, 0xee8a0a08}, {2, 0xba4237c1}, {1, 0xa70349dc}, {1, 0x344722bb}, - {3, 0xd6294733}, {2, 0xec9f5c94}, {2, 0xca2fbc28}, {1, 0x6ba4f406}, - {2, 0x015d4532}, {1, 0x6e119b7c}, {2, 0x43e8f314}, {2, 0x27962f38}, - {2, 0xb571b51b}, {2, 0xb36bee23}, {2, 0xd17924a8}, {2, 0x6bc212d9}, - {1, 0x630d4948}, {2, 0x9a4c4ebb}, {2, 0x554be537}, {1, 0xd63ddfc7}, - {2, 0xa10acc11}, {1, 0x759a8363}, {2, 0xfb73090d}, {1, 0xe82c6a34}, - {1, 0xe33e92d7}, {3, 0x658ef5cb}, {2, 0xba32ff22}, {5, 0x0227a10c}, - {1, 0xa9a70155}, {5, 0xd096d809}, {1, 0x37176174}, {1, 0x830b8d0f}, - {1, 0xc6e3910e}, {2, 0x823f3ca8}, {1, 0x99850849}, {1, 0x7521fb81}, - {1, 0xaacaabab}, {1, 0xd645a2eb}, {5, 0x7aea1781}, {5, 0x9d6e4b78}, - {1, 0x4ce90fd8}, {1, 0xabdc832d}, {6, 0x4a34f32a}, {2, 0xf2524c1c}, - {2, 0x1bbeb08a}, {1, 0xad47f480}, {1, 0x9f026aeb}, {1, 0x15a95049}, - {2, 0xd1cb95b2}, {2, 0xf84bbda5}, {1, 0x0fa62cd1}, {1, 0xe05f9169}, - {1, 0x78d194a9}, {5, 0x3e38147b}, {5, 0x737ba0d4}, {1, 0x63378e10}, - {1, 0x6d5f91cf}, {2, 0x88612eb8}, {2, 0xe9639484}, {1, 0xb7fabc9d}, - {2, 0x19b01592}, {1, 0x5a90dd31}, {2, 0x5bd7e028}, {2, 0x94d00323}, - {1, 0xa9b9c01a}, {1, 0x3a40de61}, {1, 0x56e7eec7}, {5, 0x859f7ef6}, - {1, 0xfd8e5630}, {1, 0x2b0c9f7f}, {1, 0xba700e26}, {1, 0x7170a408}, - {1, 0x70de86a8}, {1, 0x74d64cd5}, {1, 0x49e738a1}, {2, 0x6910b602}, - {0, 0x643c565f}, {1, 0x54264b3f}, {2, 0x97ea6396}, {2, 0x55174459}, - {2, 0x03e8779a}, {1, 0x98f34d8f}, {1, 0xc07b2b07}, {1, 0xdfe29668}, - {1, 0x3141c7c1}, {1, 0xb3b595f4}, {1, 0x735abf08}, {5, 0x623bfbce}, - {2, 0xd351e722}, {1, 0xf4ca48c9}, {1, 0x5b19c670}, {1, 0xa164bf0e}, + {4, 0xa4a3e223}, {2, 0x15c32f9e}, {1, 0x0375b547}, {1, 0x7004a8a5}, {2, 0xce440296}, {2, 0x52cfe198}, + {1, 0x77a72cd0}, {2, 0xbb5d6f84}, {2, 0x83f30c2c}, {1, 0x48a73d5b}, {1, 0xef7dcd01}, {2, 0x6809c6c4}, + {2, 0x0883ab3c}, {1, 0x087bbbe2}, {2, 0x2104a814}, {2, 0xdffb6daa}, {1, 0xee8a0a08}, {2, 0xba4237c1}, + {1, 0xa70349dc}, {1, 0x344722bb}, {3, 0xd6294733}, {2, 0xec9f5c94}, {2, 0xca2fbc28}, {1, 0x6ba4f406}, + {2, 0x015d4532}, {1, 0x6e119b7c}, {2, 0x43e8f314}, {2, 0x27962f38}, {2, 0xb571b51b}, {2, 0xb36bee23}, + {2, 0xd17924a8}, {2, 0x6bc212d9}, {1, 0x630d4948}, {2, 0x9a4c4ebb}, {2, 0x554be537}, {1, 0xd63ddfc7}, + {2, 0xa10acc11}, {1, 0x759a8363}, {2, 0xfb73090d}, {1, 0xe82c6a34}, {1, 0xe33e92d7}, {3, 0x658ef5cb}, + {2, 0xba32ff22}, {5, 0x0227a10c}, {1, 0xa9a70155}, {5, 0xd096d809}, {1, 0x37176174}, {1, 0x830b8d0f}, + {1, 0xc6e3910e}, {2, 0x823f3ca8}, {1, 0x99850849}, {1, 0x7521fb81}, {1, 0xaacaabab}, {1, 0xd645a2eb}, + {5, 0x7aea1781}, {5, 0x9d6e4b78}, {1, 0x4ce90fd8}, {1, 0xabdc832d}, {6, 0x4a34f32a}, {2, 0xf2524c1c}, + {2, 0x1bbeb08a}, {1, 0xad47f480}, {1, 0x9f026aeb}, {1, 0x15a95049}, {2, 0xd1cb95b2}, {2, 0xf84bbda5}, + {1, 0x0fa62cd1}, {1, 0xe05f9169}, {1, 0x78d194a9}, {5, 0x3e38147b}, {5, 0x737ba0d4}, {1, 0x63378e10}, + {1, 0x6d5f91cf}, {2, 0x88612eb8}, {2, 0xe9639484}, {1, 0xb7fabc9d}, {2, 0x19b01592}, {1, 0x5a90dd31}, + {2, 0x5bd7e028}, {2, 0x94d00323}, {1, 0xa9b9c01a}, {1, 0x3a40de61}, {1, 0x56e7eec7}, {5, 0x859f7ef6}, + {1, 0xfd8e5630}, {1, 0x2b0c9f7f}, {1, 0xba700e26}, {1, 0x7170a408}, {1, 0x70de86a8}, {1, 0x74d64cd5}, + {1, 0x49e738a1}, {2, 0x6910b602}, {0, 0x643c565f}, {1, 0x54264b3f}, {2, 0x97ea6396}, {2, 0x55174459}, + {2, 0x03e8779a}, {1, 0x98f34d8f}, {1, 0xc07b2b07}, {1, 0xdfe29668}, {1, 0x3141c7c1}, {1, 0xb3b595f4}, + {1, 0x735abf08}, {5, 0x623bfbce}, {2, 0xd351e722}, {1, 0xf4ca48c9}, {1, 0x5b19c670}, {1, 0xa164bf0e}, {2, 0xbbbeb305}, {2, 0xfe1c810a}, }; +CBlockIndex CreateBlockIndex(int nHeight) +{ + CBlockIndex index; + index.nHeight = nHeight; + index.pprev = chainActive.Tip(); + return index; +} + +bool TestSequenceLocks(const CTransaction &tx, int flags) +{ + LOCK(mempool.cs); + return CheckSequenceLocks(tx, flags); +} + // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { - CReserveKey reservekey(pwalletMain); - CBlock *pblock; - CTransaction tx; + const CChainParams &chainparams = Params(CBaseChainParams::MAIN); + CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f" + "6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") + << OP_CHECKSIG; + CBlockTemplate *pblocktemplate; + CMutableTransaction tx, tx2; CScript script; uint256 hash; + TestMemPoolEntryHelper entry; + entry.nFee = 11; + entry.dPriority = 111.0; + entry.nHeight = 11; + maxGeneratedBlock = 100000; + excessiveBlockSize = maxGeneratedBlock; + LOCK(cs_main); + fCheckpointsEnabled = false; // Simple block creation, nothing special yet: - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + + // Simple block creation, with coinbase message + settingsToUserAgentString(); + BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + + // Simple block creation, with coinbase message and miner message. + settingsToUserAgentString(); + minerComment = "I am a meat popsicle."; + BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + + minerComment = "flying is throwing yourself against the ground and missing. This comment is " + "WAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY too long."; + BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) - std::vectortxFirst; - for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i) + int baseheight = 0; + std::vector txFirst; + for (unsigned int i = 0; i < sizeof(blockinfo) / sizeof(*blockinfo); ++i) { + CBlock *pblock = &pblocktemplate->block; // pointer for convenience pblock->nVersion = 1; - pblock->nTime = pindexBest->GetMedianTimePast()+1; - pblock->vtx[0].vin[0].scriptSig = CScript(); - pblock->vtx[0].vin[0].scriptSig.push_back(blockinfo[i].extranonce); - pblock->vtx[0].vin[0].scriptSig.push_back(pindexBest->nHeight); - pblock->vtx[0].vout[0].scriptPubKey = CScript(); - if (txFirst.size() < 2) + pblock->nTime = chainActive.Tip()->GetMedianTimePast() + 1; + CMutableTransaction txCoinbase(pblock->vtx[0]); + txCoinbase.nVersion = 1; + txCoinbase.vin[0].scriptSig = CScript(); + txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce); + txCoinbase.vin[0].scriptSig.push_back(chainActive.Height()); + txCoinbase.vout[0].scriptPubKey = CScript(); + pblock->vtx[0] = CTransaction(txCoinbase); + if (txFirst.size() == 0) + baseheight = chainActive.Height(); + if (txFirst.size() < 4) txFirst.push_back(new CTransaction(pblock->vtx[0])); - pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = blockinfo[i].nonce; - assert(ProcessBlock(NULL, pblock)); + CValidationState state; + BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, false)); + BOOST_CHECK(state.IsValid()); pblock->hashPrevBlock = pblock->GetHash(); } - delete pblock; + delete pblocktemplate; // Just to make sure we can still make simple blocks - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + delete pblocktemplate; // block sigops > limit: 1000 CHECKMULTISIG + 1 tx.vin.resize(1); @@ -92,11 +144,104 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { tx.vout[0].nValue -= 1000000; hash = tx.GetHash(); - mempool.addUnchecked(hash, tx); + bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase + // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails + mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + BOOST_CHECK_THROW(BlockAssembler(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error); + mempool.clear(); + + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vout[0].nValue = 5000000000LL; + for (unsigned int i = 0; i < 1001; ++i) + { + tx.vout[0].nValue -= 1000000; + hash = tx.GetHash(); + bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase + // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes + mempool.addUnchecked( + hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOps(20).FromTx(tx)); + tx.vin[0].prevout.hash = hash; + } + BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + delete pblocktemplate; + + // Now generate lots of full size blocks and verify that none exceed the maxGeneratedBlock value, the mempool has + // 65k bytes of tx in it so this code will test both saturated and unsaturated blocks. + for (unsigned int i = 2000; i <= 80000; i += 2000) + { + maxGeneratedBlock = i; + + pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); + BOOST_CHECK(pblocktemplate); + BOOST_CHECK(pblocktemplate->block.fExcessive == false); + BOOST_CHECK(pblocktemplate->block.nBlockSize <= maxGeneratedBlock); + unsigned int blockSize = ::GetSerializeSize(pblocktemplate->block, SER_NETWORK, CBlock::CURRENT_VERSION); + BOOST_CHECK(blockSize <= maxGeneratedBlock); + // printf("%lu %lu <= %lu\n", (long unsigned int) blockSize, (long unsigned int) + // pblocktemplate->block.nBlockSize, (long unsigned int) maxGeneratedBlock); + delete pblocktemplate; + } + + BOOST_CHECK(chainActive.Tip()->nHeight == 110); + uint64_t minRoom = 1000; + + // Test no reserve and standard length miner comment + coinbaseReserve.value = 0; + minerComment = "I am a meat popsicle."; + + // Now generate lots of full size blocks and verify that none exceed the maxGeneratedBlock value + for (unsigned int i = 2000; i <= 30000; i += 67) + { + maxGeneratedBlock = i; + + pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); + BOOST_CHECK(pblocktemplate); + BOOST_CHECK(pblocktemplate->block.fExcessive == false); + BOOST_CHECK(pblocktemplate->block.nBlockSize <= maxGeneratedBlock - 4); + unsigned int blockSize = ::GetSerializeSize(pblocktemplate->block, SER_NETWORK, CBlock::CURRENT_VERSION); + BOOST_CHECK(blockSize <= maxGeneratedBlock - 4); + minRoom = std::min(minRoom, maxGeneratedBlock - blockSize); + // printf("%lu %lu <= %lu\n", (long unsigned int) blockSize, (long unsigned int) + // pblocktemplate->block.nBlockSize, (long unsigned int) maxGeneratedBlock); + delete pblocktemplate; + } + + // Assert we went right up to the limit. We reserved 4 bytes for height but only use 2 as height is 110. + // We also reserved 5 bytes for tx count but only use 3 as we don't have > 65535 txs in a block + BOOST_CHECK(minRoom == 4); + + minRoom = 1000; + std::string testMinerComment("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvw" + "xyzABCDEFGHIJKLM__________"); + // Now generate lots of full size blocks and verify that none exceed the maxGeneratedBlock value + // printf("test mining with different sized miner comments"); + for (unsigned int i = 2000; i <= 40000; i += 89) + { + maxGeneratedBlock = i; + if ((i % 100) > 0) + minerComment = testMinerComment.substr(0, i % 100); + else + minerComment = ""; + // minerComment = testMinerComment.substr(0,i%100); + pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); + BOOST_CHECK(pblocktemplate); + BOOST_CHECK(pblocktemplate->block.fExcessive == false); + BOOST_CHECK(pblocktemplate->block.nBlockSize <= maxGeneratedBlock - 2); + unsigned int blockSize = ::GetSerializeSize(pblocktemplate->block, SER_NETWORK, CBlock::CURRENT_VERSION); + BOOST_CHECK(blockSize <= maxGeneratedBlock - 2); + minRoom = std::min(minRoom, maxGeneratedBlock - blockSize); + // printf("%lu %lu (miner comment is %d) <= %lu\n", (long unsigned int) blockSize, (long unsigned int) + // pblocktemplate->block.nBlockSize, i%100, (long unsigned int) maxGeneratedBlock); + delete pblocktemplate; + } + + // Assert we went right up to the limit. We reserved 4 bytes for height but only use 2 as height is 110. + // However those 2 bytes are instead used by the long miner comment. + // We also reserved 5 bytes for tx count but only use 3 as we don't have > 65535 txs in a block + BOOST_CHECK(minRoom == 2); + mempool.clear(); // block size > limit @@ -112,18 +257,18 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { tx.vout[0].nValue -= 10000000; hash = tx.GetHash(); - mempool.addUnchecked(hash, tx); + bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase + mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + delete pblocktemplate; mempool.clear(); - // orphan in mempool + // orphan in mempool, template creation fails hash = tx.GetHash(); - mempool.addUnchecked(hash, tx); - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).FromTx(tx)); + BOOST_CHECK_THROW(BlockAssembler(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error); mempool.clear(); // child with higher priority than parent @@ -131,7 +276,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = 4900000000LL; hash = tx.GetHash(); - mempool.addUnchecked(hash, tx); + mempool.addUnchecked(hash, entry.Fee(100000000LL).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin.resize(2); tx.vin[1].scriptSig = CScript() << OP_1; @@ -139,89 +284,202 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[1].prevout.n = 0; tx.vout[0].nValue = 5900000000LL; hash = tx.GetHash(); - mempool.addUnchecked(hash, tx); - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + mempool.addUnchecked(hash, entry.Fee(400000000LL).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + delete pblocktemplate; mempool.clear(); - // coinbase in mempool + // coinbase in mempool, template creation fails tx.vin.resize(1); tx.vin[0].prevout.SetNull(); tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; tx.vout[0].nValue = 0; hash = tx.GetHash(); - mempool.addUnchecked(hash, tx); - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + // give it a fee so it'll get mined + mempool.addUnchecked(hash, entry.Fee(100000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + BOOST_CHECK_THROW(BlockAssembler(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error); mempool.clear(); - // invalid (pre-p2sh) txn in mempool + // invalid (pre-p2sh) txn in mempool, template creation fails tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript() << OP_1; tx.vout[0].nValue = 4900000000LL; script = CScript() << OP_0; - tx.vout[0].scriptPubKey.SetDestination(script.GetID()); + tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script)); hash = tx.GetHash(); - mempool.addUnchecked(hash, tx); + mempool.addUnchecked(hash, entry.Fee(10000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; - tx.vin[0].scriptSig = CScript() << (std::vector)script; + tx.vin[0].scriptSig = CScript() << std::vector(script.begin(), script.end()); tx.vout[0].nValue -= 1000000; hash = tx.GetHash(); - mempool.addUnchecked(hash,tx); - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + BOOST_CHECK_THROW(BlockAssembler(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error); mempool.clear(); - // double spend txn pair in mempool + // double spend txn pair in mempool, template creation fails tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vin[0].scriptSig = CScript() << OP_1; tx.vout[0].nValue = 4900000000LL; tx.vout[0].scriptPubKey = CScript() << OP_1; hash = tx.GetHash(); - mempool.addUnchecked(hash, tx); + mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); - mempool.addUnchecked(hash, tx); - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + BOOST_CHECK_THROW(BlockAssembler(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error); mempool.clear(); // subsidy changing - int nHeight = pindexBest->nHeight; - pindexBest->nHeight = 209999; - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; - pindexBest->nHeight = 210000; - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; - pindexBest->nHeight = nHeight; -} + int nHeight = chainActive.Height(); + // 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 = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + delete pblocktemplate; + // 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 = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + delete pblocktemplate; + // 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; + } -BOOST_AUTO_TEST_CASE(sha256transform_equality) -{ - unsigned int pSHA256InitState[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + // non-final txs in mempool + SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1); + int flags = LOCKTIME_VERIFY_SEQUENCE | LOCKTIME_MEDIAN_TIME_PAST; + // height map + std::vector prevheights; + + // relative height locked + tx.nVersion = 2; + tx.vin.resize(1); + prevheights.resize(1); + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); // only 1 transaction + tx.vin[0].prevout.n = 0; + tx.vin[0].scriptSig = CScript() << OP_1; + tx.vin[0].nSequence = chainActive.Tip()->nHeight + 1; // txFirst[0] is the 2nd block + prevheights[0] = baseheight + 1; + tx.vout.resize(1); + tx.vout[0].nValue = 4900000000LL; + tx.vout[0].scriptPubKey = CScript() << OP_1; + tx.nLockTime = 0; + hash = tx.GetHash(); + mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes + BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail + // Sequence locks pass on 2nd block + BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 2))); + + // relative time locked + tx.vin[0].prevout.hash = txFirst[1]->GetHash(); + // txFirst[1] is the 3rd block + tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | + (((chainActive.Tip()->GetMedianTimePast() + 1 - chainActive[1]->GetMedianTimePast()) >> + CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + + 1); + prevheights[0] = baseheight + 2; + hash = tx.GetHash(); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes + BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail + for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) + chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; // Trick the MedianTimePast + // Sequence locks pass 512 seconds later + BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 1))); + for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) + chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime -= 512; // undo tricked MTP - // unsigned char pstate[32]; - unsigned char pinput[64]; + // absolute height locked + tx.vin[0].prevout.hash = txFirst[2]->GetHash(); + tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1; + prevheights[0] = baseheight + 3; + tx.nLockTime = chainActive.Tip()->nHeight + 1; + hash = tx.GetHash(); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(!CheckFinalTx(tx, flags)); // Locktime fails + BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass + // Locktime passes on 2nd block + BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast())); - int i; + // absolute time locked + tx.vin[0].prevout.hash = txFirst[3]->GetHash(); + tx.nLockTime = chainActive.Tip()->GetMedianTimePast(); + prevheights.resize(1); + prevheights[0] = baseheight + 4; + hash = tx.GetHash(); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(!CheckFinalTx(tx, flags)); // Locktime fails + BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass + // Locktime passes 1 second later + BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast() + 1)); - for (i = 0; i < 32; i++) { - pinput[i] = i; - pinput[i+32] = 0; - } + // mempool-dependent transactions (not added) + tx.vin[0].prevout.hash = hash; + prevheights[0] = chainActive.Tip()->nHeight + 1; + tx.nLockTime = 0; + tx.vin[0].nSequence = 0; + BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes + BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass + tx.vin[0].nSequence = 1; + BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail + tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG; + BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass + tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1; + BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail - uint256 hash; + BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); - SHA256Transform(&hash, pinput, pSHA256InitState); + // None of the of the absolute height/time locked tx should have made + // it into the template because we still check IsFinalTx in CreateNewBlock, + // but relative locked txs will if inconsistently added to mempool. + // For now these will still generate a valid template until BIP68 soft fork + BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3); + delete pblocktemplate; + // However if we advance height by 1 and time by 512, all of them should be mined + for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) + chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; // Trick the MedianTimePast + chainActive.Tip()->nHeight++; + SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1); - BOOST_TEST_MESSAGE(hash.GetHex()); + BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5); + delete pblocktemplate; + + chainActive.Tip()->nHeight--; + SetMockTime(0); + mempool.clear(); - uint256 hash_reference("0x2df5e1c65ef9f8cde240d23cae2ec036d31a15ec64bc68f64be242b1da6631f3"); + BOOST_FOREACH (CTransaction *tx, txFirst) + delete tx; - BOOST_CHECK(hash == hash_reference); + fCheckpointsEnabled = true; } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 9c091661..4c4d0a50 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -1,41 +1,53 @@ -#include -#include -#include -#include -#include -#include - -#include -#include - +// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "base58.h" // Freeze CBitcoinAddress +#include "chain.h" // Freeze CBlockIndex +#include "key.h" #include "keystore.h" -#include "main.h" -#include "script.h" -#include "wallet.h" +#include "policy/policy.h" +#include "script/interpreter.h" +#include "script/ismine.h" +#include "script/script.h" +#include "script/script_error.h" +#include "script/sign.h" +#include "test/test_bitcoin.h" +#include "uint256.h" + +#ifdef ENABLE_WALLET +#include "wallet/wallet.h" // Freeze wallet test +#endif + +#include +#include using namespace std; -using namespace boost::assign; typedef vector valtype; -extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); -extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, int nHashType); - -BOOST_AUTO_TEST_SUITE(multisig_tests) +BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup) -CScript -sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, int whichIn) +CScript sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, int whichIn) { - uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL); +#ifdef BITCOIN_CASH + uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL | SIGHASH_FORKID, 0); +#else + uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0); +#endif CScript result; result << OP_0; // CHECKMULTISIG bug workaround - for (auto key: keys) + BOOST_FOREACH (const CKey &key, keys) { vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); +#ifdef BITCOIN_CASH + vchSig.push_back((unsigned char)SIGHASH_ALL | SIGHASH_FORKID); +#else vchSig.push_back((unsigned char)SIGHASH_ALL); +#endif result << vchSig; } return result; @@ -43,26 +55,35 @@ sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, BOOST_AUTO_TEST_CASE(multisig_verify) { +#ifdef BITCOIN_CASH + unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID; +#else + unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; +#endif + + ScriptError err; CKey key[4]; + CAmount amount = 0; for (int i = 0; i < 4; i++) key[i].MakeNewKey(true); CScript a_and_b; - a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; CScript a_or_b; - a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; CScript escrow; - escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; + escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) + << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; - CTransaction txFrom; // Funding transaction + CMutableTransaction txFrom; // Funding transaction txFrom.vout.resize(3); txFrom.vout[0].scriptPubKey = a_and_b; txFrom.vout[1].scriptPubKey = a_or_b; txFrom.vout[2].scriptPubKey = escrow; - CTransaction txTo[3]; // Spending transaction + CMutableTransaction txTo[3]; // Spending transaction for (int i = 0; i < 3; i++) { txTo[i].vin.resize(1); @@ -76,53 +97,76 @@ BOOST_AUTO_TEST_CASE(multisig_verify) CScript s; // Test a AND b: - keys.clear(); - keys += key[0],key[1]; // magic operator+= from boost.assign + keys.assign(1, key[0]); + keys.push_back(key[1]); s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, true, 0)); + BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); for (int i = 0; i < 4; i++) { - keys.clear(); - keys += key[i]; + keys.assign(1, key[i]); s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, 0), strprintf("a&b 1: %d", i)); + BOOST_CHECK_MESSAGE( + !VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), + strprintf("a&b 1: %d", i)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); - keys.clear(); - keys += key[1],key[i]; + keys.assign(1, key[1]); + keys.push_back(key[i]); s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, 0), strprintf("a&b 2: %d", i)); + BOOST_CHECK_MESSAGE( + !VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), + strprintf("a&b 2: %d", i)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } // Test a OR b: for (int i = 0; i < 4; i++) { - keys.clear(); - keys += key[i]; + keys.assign(1, key[i]); s = sign_multisig(a_or_b, keys, txTo[1], 0); if (i == 0 || i == 1) - BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, true, 0), strprintf("a|b: %d", i)); + { + BOOST_CHECK_MESSAGE( + VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), + strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); + } else - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0), strprintf("a|b: %d", i)); + { + BOOST_CHECK_MESSAGE( + !VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), + strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); + } } s.clear(); - s << OP_0 << OP_0; - BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0)); - s.clear(); s << OP_0 << OP_1; - BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0)); + BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err)); for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) { - keys.clear(); - keys += key[i],key[j]; + keys.assign(1, key[i]); + keys.push_back(key[j]); s = sign_multisig(escrow, keys, txTo[2], 0); if (i < j && i < 3 && j < 3) - BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, true, 0), strprintf("escrow 1: %d %d", i, j)); + { + BOOST_CHECK_MESSAGE( + VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), + strprintf("escrow 1: %d %d", i, j)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); + } else - BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, true, 0), strprintf("escrow 2: %d %d", i, j)); + { + BOOST_CHECK_MESSAGE( + !VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), + strprintf("escrow 2: %d %d", i, j)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); + } } } @@ -132,32 +176,40 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard) for (int i = 0; i < 4; i++) key[i].MakeNewKey(true); + txnouttype whichType; + CScript a_and_b; - a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(::IsStandard(a_and_b)); + a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK(::IsStandard(a_and_b, whichType)); CScript a_or_b; - a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(::IsStandard(a_or_b)); + a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK(::IsStandard(a_or_b, whichType)); CScript escrow; - escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; - BOOST_CHECK(::IsStandard(escrow)); + escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) + << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; + BOOST_CHECK(::IsStandard(escrow, whichType)); CScript one_of_four; - one_of_four << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << key[3].GetPubKey() << OP_4 << OP_CHECKMULTISIG; - BOOST_CHECK(!::IsStandard(one_of_four)); + one_of_four << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) + << ToByteVector(key[2].GetPubKey()) << ToByteVector(key[3].GetPubKey()) << OP_4 << OP_CHECKMULTISIG; + BOOST_CHECK(!::IsStandard(one_of_four, whichType)); CScript malformed[6]; - malformed[0] << OP_3 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; - malformed[1] << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_3 << OP_CHECKMULTISIG; - malformed[2] << OP_0 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; - malformed[3] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_0 << OP_CHECKMULTISIG; - malformed[4] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_CHECKMULTISIG; - malformed[5] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey(); + malformed[0] << OP_3 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 + << OP_CHECKMULTISIG; + malformed[1] << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_3 + << OP_CHECKMULTISIG; + malformed[2] << OP_0 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 + << OP_CHECKMULTISIG; + malformed[3] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_0 + << OP_CHECKMULTISIG; + malformed[4] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_CHECKMULTISIG; + malformed[5] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()); for (int i = 0; i < 6; i++) - BOOST_CHECK(!::IsStandard(malformed[i])); + BOOST_CHECK(!::IsStandard(malformed[i], whichType)); } BOOST_AUTO_TEST_CASE(multisig_Solver1) @@ -165,9 +217,9 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) // Tests Solver() that returns lists of keys that are // required to satisfy a ScriptPubKey // - // Also tests IsMine() and ExtractAddress() + // Also tests IsMine() and ExtractDestination() // - // Note: ExtractAddress for the multisignature transactions + // Note: ExtractDestination for the multisignature transactions // always returns false for this release, even if you have // one key that would satisfy an (a|b) or 2-of-3 keys needed // to spend an escrow transaction. @@ -187,63 +239,76 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) vector solutions; txnouttype whichType; CScript s; - s << key[0].GetPubKey() << OP_CHECKSIG; + s << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK(solutions.size() == 1); CTxDestination addr; BOOST_CHECK(ExtractDestination(s, addr)); BOOST_CHECK(addr == keyaddr[0]); - BOOST_CHECK(IsMine(keystore, s)); - BOOST_CHECK(!IsMine(emptykeystore, s)); +#ifdef ENABLE_WALLET + CBlockIndex *nullBestBlock = nullptr; + BOOST_CHECK(IsMine(keystore, s, nullBestBlock)); + BOOST_CHECK(!IsMine(emptykeystore, s, nullBestBlock)); +#endif } { vector solutions; txnouttype whichType; CScript s; - s << OP_DUP << OP_HASH160 << key[0].GetPubKey().GetID() << OP_EQUALVERIFY << OP_CHECKSIG; + s << OP_DUP << OP_HASH160 << ToByteVector(key[0].GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK(solutions.size() == 1); CTxDestination addr; BOOST_CHECK(ExtractDestination(s, addr)); BOOST_CHECK(addr == keyaddr[0]); - BOOST_CHECK(IsMine(keystore, s)); - BOOST_CHECK(!IsMine(emptykeystore, s)); +#ifdef ENABLE_WALLET + CBlockIndex *nullBestBlock = nullptr; + BOOST_CHECK(IsMine(keystore, s, nullBestBlock)); + BOOST_CHECK(!IsMine(emptykeystore, s, nullBestBlock)); +#endif } { vector solutions; txnouttype whichType; CScript s; - s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(solutions.size(), 4); + BOOST_CHECK_EQUAL(solutions.size(), 4U); CTxDestination addr; BOOST_CHECK(!ExtractDestination(s, addr)); - BOOST_CHECK(IsMine(keystore, s)); - BOOST_CHECK(!IsMine(emptykeystore, s)); - BOOST_CHECK(!IsMine(partialkeystore, s)); +#ifdef ENABLE_WALLET + CBlockIndex *nullBestBlock = nullptr; + BOOST_CHECK(IsMine(keystore, s, nullBestBlock)); + BOOST_CHECK(!IsMine(emptykeystore, s, nullBestBlock)); + BOOST_CHECK(!IsMine(partialkeystore, s, nullBestBlock)); +#endif } { vector solutions; txnouttype whichType; CScript s; - s << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + s << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(solutions.size(), 4); + BOOST_CHECK_EQUAL(solutions.size(), 4U); vector addrs; int nRequired; BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired)); BOOST_CHECK(addrs[0] == keyaddr[0]); BOOST_CHECK(addrs[1] == keyaddr[1]); BOOST_CHECK(nRequired == 1); - BOOST_CHECK(IsMine(keystore, s)); - BOOST_CHECK(!IsMine(emptykeystore, s)); - BOOST_CHECK(!IsMine(partialkeystore, s)); +#ifdef ENABLE_WALLET + CBlockIndex *nullBestBlock = nullptr; + BOOST_CHECK(IsMine(keystore, s, nullBestBlock)); + BOOST_CHECK(!IsMine(emptykeystore, s, nullBestBlock)); + BOOST_CHECK(!IsMine(partialkeystore, s, nullBestBlock)); +#endif } { vector solutions; txnouttype whichType; CScript s; - s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; + s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) + << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK(solutions.size() == 5); } @@ -261,21 +326,22 @@ BOOST_AUTO_TEST_CASE(multisig_Sign) } CScript a_and_b; - a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; CScript a_or_b; - a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; CScript escrow; - escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; + escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) + << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; - CTransaction txFrom; // Funding transaction + CMutableTransaction txFrom; // Funding transaction txFrom.vout.resize(3); txFrom.vout[0].scriptPubKey = a_and_b; txFrom.vout[1].scriptPubKey = a_or_b; txFrom.vout[2].scriptPubKey = escrow; - CTransaction txTo[3]; // Spending transaction + CMutableTransaction txTo[3]; // Spending transaction for (int i = 0; i < 3; i++) { txTo[i].vin.resize(1); @@ -291,5 +357,80 @@ BOOST_AUTO_TEST_CASE(multisig_Sign) } } +#ifdef ENABLE_WALLET +BOOST_AUTO_TEST_CASE(cltv_freeze) +{ + CKey key[4]; + for (int i = 0; i < 2; i++) + key[i].MakeNewKey(true); + + // Create and unpack a CLTV script + vector solutions; + txnouttype whichType; + vector addresses; + int nRequiredReturn; + txnouttype type = TX_CLTV; + + // check cltv solve for block + CPubKey newKey1 = ToByteVector(key[0].GetPubKey()); + CBitcoinAddress newAddr1(newKey1.GetID()); + CScriptNum nFreezeLockTime(50000); + CScript s1 = GetScriptForFreeze(nFreezeLockTime, newKey1); + + BOOST_CHECK(Solver(s1, whichType, solutions)); + BOOST_CHECK(whichType == TX_CLTV); + BOOST_CHECK(solutions.size() == 2); + BOOST_CHECK(CScriptNum(solutions[0], false) == nFreezeLockTime); + + nRequiredReturn = 0; + ExtractDestinations(s1, type, addresses, nRequiredReturn); + BOOST_FOREACH (const CTxDestination &addr, addresses) + BOOST_CHECK(newAddr1.ToString() == CBitcoinAddress(addr).ToString()); + + BOOST_CHECK(nRequiredReturn == 1); + + + // check cltv solve for datetime + CPubKey newKey2 = ToByteVector(key[0].GetPubKey()); + CBitcoinAddress newAddr2(newKey2.GetID()); + nFreezeLockTime = CScriptNum(1482255731); + CScript s2 = GetScriptForFreeze(nFreezeLockTime, newKey2); + + BOOST_CHECK(Solver(s2, whichType, solutions)); + BOOST_CHECK(whichType == TX_CLTV); + BOOST_CHECK(solutions.size() == 2); + BOOST_CHECK(CScriptNum(solutions[0], false) == nFreezeLockTime); + + nRequiredReturn = 0; + ExtractDestinations(s2, type, addresses, nRequiredReturn); + + BOOST_FOREACH (const CTxDestination &addr, addresses) + BOOST_CHECK(newAddr2.ToString() == CBitcoinAddress(addr).ToString()); + + BOOST_CHECK(nRequiredReturn == 1); +} + +BOOST_AUTO_TEST_CASE(opreturn_send) +{ + CKey key[4]; + for (int i = 0; i < 2; i++) + key[i].MakeNewKey(true); + + CBasicKeyStore keystore; + + // Create and unpack a CLTV script + vector solutions; + txnouttype whichType; + vector addresses; + + string inMsg = "hello world", outMsg = ""; + CScript s = GetScriptLabelPublic(inMsg); + + outMsg = getLabelPublic(s); + BOOST_CHECK(inMsg == outMsg); + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK(whichType == TX_LABELPUBLIC); +} +#endif BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp new file mode 100644 index 00000000..c01b6a2a --- /dev/null +++ b/src/test/net_tests.cpp @@ -0,0 +1,216 @@ +// Copyright (c) 2012-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 "net.h" +#include "addrman.h" +#include "chainparams.h" +#include "hash.h" +#include "serialize.h" +#include "streams.h" +#include "test/test_bitcoin.h" +#include +#include + +using namespace std; + +class CAddrManSerializationMock : public CAddrMan +{ +public: + virtual void Serialize(CDataStream &s) const = 0; + + //! Ensure that bucket placement is always the same for testing purposes. + void MakeDeterministic() + { + nKey.SetNull(); + seed_insecure_rand(true); + } +}; + +class CAddrManUncorrupted : public CAddrManSerializationMock +{ +public: + void Serialize(CDataStream &s) const { CAddrMan::Serialize(s); } +}; + +class CAddrManCorrupted : public CAddrManSerializationMock +{ +public: + void Serialize(CDataStream &s) const + { + // Produces corrupt output that claims addrman has 20 addrs when it only has one addr. + unsigned char nVersion = 1; + s << nVersion; + s << uint8_t(32); + s << nKey; + s << 10; // nNew + s << 10; // nTried + + int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30); + s << nUBuckets; + + CAddress addr = CAddress(CService("252.1.1.1", 7777)); + CAddrInfo info = CAddrInfo(addr, CNetAddr("252.2.2.2")); + s << info; + } +}; + +CDataStream AddrmanToStream(CAddrManSerializationMock &addrman) +{ + CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION); + ssPeersIn << FLATDATA(Params().MessageStart()); + ssPeersIn << addrman; + std::string str = ssPeersIn.str(); + std::vector vchData(str.begin(), str.end()); + return CDataStream(vchData, SER_DISK, CLIENT_VERSION); +} + +BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(caddrdb_read) +{ + CAddrManUncorrupted addrmanUncorrupted; + addrmanUncorrupted.MakeDeterministic(); + + CService addr1 = CService("250.7.1.1", 8333); + CService addr2 = CService("250.7.2.2", 9999); + CService addr3 = CService("250.7.3.3", 9999); + + // Add three addresses to new table. + addrmanUncorrupted.Add(CAddress(addr1), CService("252.5.1.1", 8333)); + addrmanUncorrupted.Add(CAddress(addr2), CService("252.5.1.1", 8333)); + addrmanUncorrupted.Add(CAddress(addr3), CService("252.5.1.1", 8333)); + + // Test that the de-serialization does not throw an exception. + CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted); + bool exceptionThrown = false; + CAddrMan addrman1; + + BOOST_CHECK(addrman1.size() == 0); + try + { + uint8_t pchMsgTmp[4]; + ssPeers1 >> FLATDATA(pchMsgTmp); + ssPeers1 >> addrman1; + } + catch (const std::exception &e) + { + exceptionThrown = true; + } + + BOOST_CHECK(addrman1.size() == 3); + BOOST_CHECK(exceptionThrown == false); + + // Test that CAddrDB::Read creates an addrman with the correct number of addrs. + CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted); + + CAddrMan addrman2; + CAddrDB adb; + BOOST_CHECK(addrman2.size() == 0); + adb.Read(addrman2, ssPeers2); + BOOST_CHECK(addrman2.size() == 3); +} + + +BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted) +{ + CAddrManCorrupted addrmanCorrupted; + addrmanCorrupted.MakeDeterministic(); + + // Test that the de-serialization of corrupted addrman throws an exception. + CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted); + bool exceptionThrown = false; + CAddrMan addrman1; + BOOST_CHECK(addrman1.size() == 0); + try + { + uint8_t pchMsgTmp[4]; + ssPeers1 >> FLATDATA(pchMsgTmp); + ssPeers1 >> addrman1; + } + catch (const std::exception &e) + { + exceptionThrown = true; + } + // Even through de-serialization failed addrman is not left in a clean state. + BOOST_CHECK(addrman1.size() == 1); + BOOST_CHECK(exceptionThrown); + + // Test that CAddrDB::Read leaves addrman in a clean state if de-serialization fails. + CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted); + + CAddrMan addrman2; + CAddrDB adb; + BOOST_CHECK(addrman2.size() == 0); + adb.Read(addrman2, ssPeers2); + BOOST_CHECK(addrman2.size() == 0); +} + +BOOST_AUTO_TEST_CASE(cnode_simple_test) +{ + SOCKET hSocket = INVALID_SOCKET; + + in_addr ipv4Addr; + ipv4Addr.s_addr = 0xa0b0c001; + + CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK); + std::string pszDest = ""; + bool fInboundIn = false; + + // Test that fFeeler is false by default. + std::unique_ptr pnode1(new CNode(hSocket, addr, pszDest, fInboundIn)); + BOOST_CHECK(pnode1->fInbound == false); + BOOST_CHECK(pnode1->fFeeler == false); + + fInboundIn = true; + std::unique_ptr pnode2(new CNode(hSocket, addr, pszDest, fInboundIn)); + BOOST_CHECK(pnode2->fInbound == true); + BOOST_CHECK(pnode2->fFeeler == false); + + // NodeRef checks and refcount checks. + BOOST_CHECK_EQUAL(pnode1->nRefCount, 0); + + // Check null pointers are good + { + CNodeRef ref; // Default constructor + BOOST_CHECK(!ref); // operator bool + ref = 0; + BOOST_CHECK(!ref); + } + + // get() + { + CNodeRef ref1(pnode1.get()); + CNodeRef ref2; + BOOST_CHECK(ref1.get() == pnode1.get()); + BOOST_CHECK(ref2.get() == nullptr); + } + + // Plain constructor and copy constructor + { + CNodeRef ref1(pnode1.get()); + BOOST_CHECK_EQUAL(pnode1->nRefCount, 1); + + { + CNodeRef ref2(ref1); + BOOST_CHECK_EQUAL(pnode1->nRefCount, 2); + } + + BOOST_CHECK_EQUAL(pnode1->nRefCount, 1); + } + BOOST_CHECK_EQUAL(pnode1->nRefCount, 0); + + // Assignment operator + { + CNodeRef ref1; + + ref1 = pnode1.get(); + BOOST_CHECK_EQUAL(pnode1->nRefCount, 1); + ref1 = ref1; + BOOST_CHECK_EQUAL(pnode1->nRefCount, 1); + ref1 = nullptr; + BOOST_CHECK_EQUAL(pnode1->nRefCount, 0); + } + BOOST_CHECK_EQUAL(pnode1->nRefCount, 0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index e5a7562d..793ccc41 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -1,20 +1,27 @@ -#include +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "netbase.h" +#include "netaddress.h" +#include "test/test_bitcoin.h" #include -#include -#include "netbase.h" +#include +#include using namespace std; -BOOST_AUTO_TEST_SUITE(netbase_tests) +BOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(netbase_networks) { - BOOST_CHECK(CNetAddr("127.0.0.1").GetNetwork() == NET_UNROUTABLE); - BOOST_CHECK(CNetAddr("::1").GetNetwork() == NET_UNROUTABLE); - BOOST_CHECK(CNetAddr("8.8.8.8").GetNetwork() == NET_IPV4); - BOOST_CHECK(CNetAddr("2001::8888").GetNetwork() == NET_IPV6); + BOOST_CHECK(CNetAddr("127.0.0.1").GetNetwork() == NET_UNROUTABLE); + BOOST_CHECK(CNetAddr("::1").GetNetwork() == NET_UNROUTABLE); + BOOST_CHECK(CNetAddr("8.8.8.8").GetNetwork() == NET_IPV4); + BOOST_CHECK(CNetAddr("2001::8888").GetNetwork() == NET_IPV6); BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR); } @@ -90,7 +97,7 @@ BOOST_AUTO_TEST_CASE(netbase_lookupnumeric) BOOST_AUTO_TEST_CASE(onioncat_test) { - // values from http://www.cypherpunk.at/onioncat/wiki/OnionCat + // values from https://web.archive.org/web/20121122003543/http://www.cypherpunk.at/onioncat/wiki/OnionCat CNetAddr addr1("5wyqrzbvrdsumnok.onion"); CNetAddr addr2("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca"); BOOST_CHECK(addr1 == addr2); @@ -99,4 +106,163 @@ BOOST_AUTO_TEST_CASE(onioncat_test) BOOST_CHECK(addr1.IsRoutable()); } +BOOST_AUTO_TEST_CASE(subnet_test) +{ + BOOST_CHECK(CSubNet("1.2.3.0/24") == CSubNet("1.2.3.0/255.255.255.0")); + BOOST_CHECK(CSubNet("1.2.3.0/24") != CSubNet("1.2.4.0/255.255.255.0")); + BOOST_CHECK(CSubNet("1.2.3.0/24").Match(CNetAddr("1.2.3.4"))); + BOOST_CHECK(!CSubNet("1.2.2.0/24").Match(CNetAddr("1.2.3.4"))); + BOOST_CHECK(CSubNet("1.2.3.4").Match(CNetAddr("1.2.3.4"))); + BOOST_CHECK(CSubNet("1.2.3.4/32").Match(CNetAddr("1.2.3.4"))); + BOOST_CHECK(!CSubNet("1.2.3.4").Match(CNetAddr("5.6.7.8"))); + BOOST_CHECK(!CSubNet("1.2.3.4/32").Match(CNetAddr("5.6.7.8"))); + BOOST_CHECK(CSubNet("::ffff:127.0.0.1").Match(CNetAddr("127.0.0.1"))); + BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8").Match(CNetAddr("1:2:3:4:5:6:7:8"))); + BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8").Match(CNetAddr("1:2:3:4:5:6:7:9"))); + BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:0/112").Match(CNetAddr("1:2:3:4:5:6:7:1234"))); + BOOST_CHECK(CSubNet("192.168.0.1/24").Match(CNetAddr("192.168.0.2"))); + BOOST_CHECK(CSubNet("192.168.0.20/29").Match(CNetAddr("192.168.0.18"))); + BOOST_CHECK(CSubNet("1.2.2.1/24").Match(CNetAddr("1.2.2.4"))); + BOOST_CHECK(CSubNet("1.2.2.110/31").Match(CNetAddr("1.2.2.111"))); + BOOST_CHECK(CSubNet("1.2.2.20/26").Match(CNetAddr("1.2.2.63"))); + // All-Matching IPv6 Matches arbitrary IPv4 and IPv6 + BOOST_CHECK(CSubNet("::/0").Match(CNetAddr("1:2:3:4:5:6:7:1234"))); + BOOST_CHECK(CSubNet("::/0").Match(CNetAddr("1.2.3.4"))); + // All-Matching IPv4 does not Match IPv6 + BOOST_CHECK(!CSubNet("0.0.0.0/0").Match(CNetAddr("1:2:3:4:5:6:7:1234"))); + // Invalid subnets Match nothing (not even invalid addresses) + BOOST_CHECK(!CSubNet().Match(CNetAddr("1.2.3.4"))); + BOOST_CHECK(!CSubNet("").Match(CNetAddr("4.5.6.7"))); + BOOST_CHECK(!CSubNet("bloop").Match(CNetAddr("0.0.0.0"))); + BOOST_CHECK(!CSubNet("bloop").Match(CNetAddr("hab"))); + // Check valid/invalid + BOOST_CHECK(CSubNet("1.2.3.0/0").IsValid()); + BOOST_CHECK(!CSubNet("1.2.3.0/-1").IsValid()); + BOOST_CHECK(CSubNet("1.2.3.0/32").IsValid()); + BOOST_CHECK(!CSubNet("1.2.3.0/33").IsValid()); + BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/0").IsValid()); + BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/33").IsValid()); + BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8/-1").IsValid()); + BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/128").IsValid()); + BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8/129").IsValid()); + BOOST_CHECK(!CSubNet("fuzzy").IsValid()); + + // CNetAddr constructor test + BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).IsValid()); + BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).Match(CNetAddr("127.0.0.1"))); + BOOST_CHECK(!CSubNet(CNetAddr("127.0.0.1")).Match(CNetAddr("127.0.0.2"))); + BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).ToString() == "127.0.0.1/32"); + + BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).IsValid()); + BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).Match(CNetAddr("1:2:3:4:5:6:7:8"))); + BOOST_CHECK(!CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).Match(CNetAddr("1:2:3:4:5:6:7:9"))); + BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).ToString() == "1:2:3:4:5:6:7:8/128"); + + CSubNet subnet = CSubNet("1.2.3.4/255.255.255.255"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32"); + subnet = CSubNet("1.2.3.4/255.255.255.254"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/31"); + subnet = CSubNet("1.2.3.4/255.255.255.252"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/30"); + subnet = CSubNet("1.2.3.4/255.255.255.248"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/29"); + subnet = CSubNet("1.2.3.4/255.255.255.240"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/28"); + subnet = CSubNet("1.2.3.4/255.255.255.224"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/27"); + subnet = CSubNet("1.2.3.4/255.255.255.192"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/26"); + subnet = CSubNet("1.2.3.4/255.255.255.128"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/25"); + subnet = CSubNet("1.2.3.4/255.255.255.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/24"); + subnet = CSubNet("1.2.3.4/255.255.254.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.2.0/23"); + subnet = CSubNet("1.2.3.4/255.255.252.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/22"); + subnet = CSubNet("1.2.3.4/255.255.248.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/21"); + subnet = CSubNet("1.2.3.4/255.255.240.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/20"); + subnet = CSubNet("1.2.3.4/255.255.224.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/19"); + subnet = CSubNet("1.2.3.4/255.255.192.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/18"); + subnet = CSubNet("1.2.3.4/255.255.128.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/17"); + subnet = CSubNet("1.2.3.4/255.255.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/16"); + subnet = CSubNet("1.2.3.4/255.254.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/15"); + subnet = CSubNet("1.2.3.4/255.252.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/14"); + subnet = CSubNet("1.2.3.4/255.248.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/13"); + subnet = CSubNet("1.2.3.4/255.240.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/12"); + subnet = CSubNet("1.2.3.4/255.224.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/11"); + subnet = CSubNet("1.2.3.4/255.192.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/10"); + subnet = CSubNet("1.2.3.4/255.128.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/9"); + subnet = CSubNet("1.2.3.4/255.0.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8"); + subnet = CSubNet("1.2.3.4/254.0.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/7"); + subnet = CSubNet("1.2.3.4/252.0.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/6"); + subnet = CSubNet("1.2.3.4/248.0.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/5"); + subnet = CSubNet("1.2.3.4/240.0.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/4"); + subnet = CSubNet("1.2.3.4/224.0.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/3"); + subnet = CSubNet("1.2.3.4/192.0.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/2"); + subnet = CSubNet("1.2.3.4/128.0.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/1"); + subnet = CSubNet("1.2.3.4/0.0.0.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0"); + + subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/128"); + subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:0000:0000:0000:0000:0000:0000:0000"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1::/16"); + subnet = CSubNet("1:2:3:4:5:6:7:8/0000:0000:0000:0000:0000:0000:0000:0000"); + BOOST_CHECK_EQUAL(subnet.ToString(), "::/0"); + subnet = CSubNet("1.2.3.4/255.255.232.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/255.255.232.0"); + subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f"); +} + +BOOST_AUTO_TEST_CASE(netbase_getgroup) +{ + BOOST_CHECK(CNetAddr("127.0.0.1").GetGroup() == boost::assign::list_of(0)); // Local -> !Routable() + BOOST_CHECK(CNetAddr("257.0.0.1").GetGroup() == boost::assign::list_of(0)); // !Valid -> !Routable() + BOOST_CHECK(CNetAddr("10.0.0.1").GetGroup() == boost::assign::list_of(0)); // RFC1918 -> !Routable() + BOOST_CHECK(CNetAddr("169.254.1.1").GetGroup() == boost::assign::list_of(0)); // RFC3927 -> !Routable() + BOOST_CHECK(CNetAddr("1.2.3.4").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // IPv4 + // RFC6145 + BOOST_CHECK(CNetAddr("::FFFF:0:102:304").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); + // RFC6052 + BOOST_CHECK(CNetAddr("64:FF9B::102:304").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); + // RFC3964 + BOOST_CHECK(CNetAddr("2002:102:304:9999:9999:9999:9999:9999").GetGroup() == + boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); + // RFC4380 + BOOST_CHECK(CNetAddr("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup() == + boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); + // Tor + BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetGroup() == + boost::assign::list_of((unsigned char)NET_TOR)(239)); + // he.net + BOOST_CHECK(CNetAddr("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup() == + boost::assign::list_of((unsigned char)NET_IPV6)(32)(1)(4)(112)(175)); + // IPv6 + BOOST_CHECK(CNetAddr("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup() == + boost::assign::list_of((unsigned char)NET_IPV6)(32)(1)(32)(1)); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp new file mode 100644 index 00000000..5741bb01 --- /dev/null +++ b/src/test/pmt_tests.cpp @@ -0,0 +1,135 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "arith_uint256.h" +#include "consensus/merkle.h" +#include "merkleblock.h" +#include "random.h" +#include "serialize.h" +#include "streams.h" +#include "test/test_bitcoin.h" +#include "uint256.h" +#include "version.h" + +#include + +#include +#include + +using namespace std; + +class CPartialMerkleTreeTester : public CPartialMerkleTree +{ +public: + // flip one bit in one of the hashes - this should break the authentication + void Damage() + { + unsigned int n = insecure_rand() % vHash.size(); + int bit = insecure_rand() % 256; + *(vHash[n].begin() + (bit >> 3)) ^= 1 << (bit & 7); + } +}; + +BOOST_FIXTURE_TEST_SUITE(pmt_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(pmt_test1) +{ + seed_insecure_rand(false); + static const unsigned int nTxCounts[] = {1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095}; + + for (int n = 0; n < 12; n++) + { + unsigned int nTx = nTxCounts[n]; + + // build a block with some dummy transactions + CBlock block; + for (unsigned int j = 0; j < nTx; j++) + { + CMutableTransaction tx; + tx.nLockTime = j; // actual transaction data doesn't matter; just make the nLockTime's unique + block.vtx.push_back(CTransaction(tx)); + } + + // calculate actual merkle root and height + uint256 merkleRoot1 = BlockMerkleRoot(block); + std::vector vTxid(nTx, uint256()); + for (unsigned int j = 0; j < nTx; j++) + vTxid[j] = block.vtx[j].GetHash(); + int nHeight = 1, nTx_ = nTx; + while (nTx_ > 1) + { + nTx_ = (nTx_ + 1) / 2; + nHeight++; + } + + // check with random subsets with inclusion chances 1, 1/2, 1/4, ..., 1/128 + for (int att = 1; att < 15; att++) + { + // build random subset of txid's + std::vector vMatch(nTx, false); + std::vector vMatchTxid1; + for (unsigned int j = 0; j < nTx; j++) + { + bool fInclude = (insecure_rand() & ((1 << (att / 2)) - 1)) == 0; + vMatch[j] = fInclude; + if (fInclude) + vMatchTxid1.push_back(vTxid[j]); + } + + // build the partial merkle tree + CPartialMerkleTree pmt1(vTxid, vMatch); + + // serialize + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << pmt1; + + // verify CPartialMerkleTree's size guarantees + unsigned int n = std::min(nTx, 1 + vMatchTxid1.size() * nHeight); + BOOST_CHECK(ss.size() <= 10 + (258 * n + 7) / 8); + + // deserialize into a tester copy + CPartialMerkleTreeTester pmt2; + ss >> pmt2; + + // extract merkle root and matched txids from copy + std::vector vMatchTxid2; + std::vector vIndex; + uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2, vIndex); + + // check that it has the same merkle root as the original, and a valid one + BOOST_CHECK(merkleRoot1 == merkleRoot2); + BOOST_CHECK(!merkleRoot2.IsNull()); + + // check that it contains the matched transactions (in the same order!) + BOOST_CHECK(vMatchTxid1 == vMatchTxid2); + + // check that random bit flips break the authentication + for (int j = 0; j < 4; j++) + { + CPartialMerkleTreeTester pmt3(pmt2); + pmt3.Damage(); + std::vector vMatchTxid3; + uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3, vIndex); + BOOST_CHECK(merkleRoot3 != merkleRoot1); + } + } + } +} + +BOOST_AUTO_TEST_CASE(pmt_malleability) +{ + std::vector vTxid = boost::assign::list_of(ArithToUint256(1))(ArithToUint256(2))(ArithToUint256(3))( + ArithToUint256(4))(ArithToUint256(5))(ArithToUint256(6))(ArithToUint256(7))(ArithToUint256(8))( + ArithToUint256(9))(ArithToUint256(10))(ArithToUint256(9))(ArithToUint256(10)); + std::vector vMatch = + boost::assign::list_of(false)(false)(false)(false)(false)(false)(false)(false)(false)(true)(true)(false); + + CPartialMerkleTree tree(vTxid, vMatch); + std::vector vTxid2; + std::vector vIndex; + BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull()); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp new file mode 100644 index 00000000..c0d0aa68 --- /dev/null +++ b/src/test/policyestimator_tests.cpp @@ -0,0 +1,247 @@ +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "policy/fees.h" +#include "txmempool.h" +#include "uint256.h" +#include "util.h" + +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) +{ + CTxMemPool mpool(CFeeRate(1000)); + TestMemPoolEntryHelper entry; + CAmount basefee(2000); + double basepri = 1e6; + CAmount deltaFee(100); + double deltaPri = 5e5; + std::vector feeV[2]; + std::vector priV[2]; + + // Populate vectors of increasing fees or priorities + for (int j = 0; j < 10; j++) + { + // V[0] is for fee transactions + feeV[0].push_back(basefee * (j + 1)); + priV[0].push_back(0); + // V[1] is for priority transactions + feeV[1].push_back(CAmount(0)); + priV[1].push_back(basepri * pow(10, j + 1)); + } + + // Store the hashes of transactions that have been + // added to the mempool by their associate fee/pri + // txHashes[j] is populated with transactions either of + // fee = basefee * (j+1) OR pri = 10^6 * 10^(j+1) + std::vector txHashes[10]; + + // Create a transaction template + CScript garbage; + for (unsigned int i = 0; i < 128; i++) + garbage.push_back('X'); + CMutableTransaction tx; + std::list dummyConflicted; + tx.vin.resize(1); + tx.vin[0].scriptSig = garbage; + tx.vout.resize(1); + tx.vout[0].nValue = 0LL; + CFeeRate baseRate(basefee, ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)); + + // Create a fake block + std::vector block; + int blocknum = 0; + + // Loop through 200 blocks + // At a decay .998 and 4 fee transactions per block + // This makes the tx count about 1.33 per bucket, above the 1 threshold + while (blocknum < 200) + { + for (int j = 0; j < 10; j++) + { // For each fee/pri multiple + for (int k = 0; k < 5; k++) + { // add 4 fee txs for every priority tx + tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k; // make transaction unique + uint256 hash = tx.GetHash(); + mpool.addUnchecked(hash, entry.Fee(feeV[k / 4][j]) + .Time(GetTime()) + .Priority(priV[k / 4][j]) + .Height(blocknum) + .FromTx(tx, &mpool)); + txHashes[j].push_back(hash); + } + } + // Create blocks where higher fee/pri txs are included more often + for (int h = 0; h <= blocknum % 10; h++) + { + // 10/10 blocks add highest fee/pri transactions + // 9/10 blocks add 2nd highest and so on until ... + // 1/10 blocks add lowest fee/pri transactions + while (txHashes[9 - h].size()) + { + CTransaction btx; + if (mpool.lookup(txHashes[9 - h].back(), btx)) + block.push_back(btx); + txHashes[9 - h].pop_back(); + } + } + mpool.removeForBlock(block, ++blocknum, dummyConflicted); + block.clear(); + if (blocknum == 30) + { + // At this point we should need to combine 5 buckets to get enough data points + // So estimateFee(1,2,3) should fail and estimateFee(4) should return somewhere around + // 8*baserate. estimateFee(4) %'s are 100,100,100,100,90 = average 98% + BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0)); + BOOST_CHECK(mpool.estimateFee(2) == CFeeRate(0)); + BOOST_CHECK(mpool.estimateFee(3) == CFeeRate(0)); + BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() < 8 * baseRate.GetFeePerK() + deltaFee); + BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() > 8 * baseRate.GetFeePerK() - deltaFee); + int answerFound; + BOOST_CHECK(mpool.estimateSmartFee(1, &answerFound) == mpool.estimateFee(4) && answerFound == 4); + BOOST_CHECK(mpool.estimateSmartFee(3, &answerFound) == mpool.estimateFee(4) && answerFound == 4); + BOOST_CHECK(mpool.estimateSmartFee(4, &answerFound) == mpool.estimateFee(4) && answerFound == 4); + BOOST_CHECK(mpool.estimateSmartFee(8, &answerFound) == mpool.estimateFee(8) && answerFound == 8); + } + } + + std::vector origFeeEst; + std::vector origPriEst; + // Highest feerate is 10*baseRate and gets in all blocks, + // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%, + // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%, + // so estimateFee(1) should return 10*baseRate. + // Second highest feerate has 100% chance of being included by 2 blocks, + // so estimateFee(2) should return 9*baseRate etc... + for (int i = 1; i < 10; i++) + { + origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK()); + origPriEst.push_back(mpool.estimatePriority(i)); + if (i > 1) + { // Fee estimates should be monotonically decreasing + BOOST_CHECK(origFeeEst[i - 1] <= origFeeEst[i - 2]); + BOOST_CHECK(origPriEst[i - 1] <= origPriEst[i - 2]); + } + int mult = 11 - i; + BOOST_CHECK(origFeeEst[i - 1] < mult * baseRate.GetFeePerK() + deltaFee); + BOOST_CHECK(origFeeEst[i - 1] > mult * baseRate.GetFeePerK() - deltaFee); + BOOST_CHECK(origPriEst[i - 1] < pow(10, mult) * basepri + deltaPri); + BOOST_CHECK(origPriEst[i - 1] > pow(10, mult) * basepri - deltaPri); + } + + // Mine 50 more blocks with no transactions happening, estimates shouldn't change + // We haven't decayed the moving average enough so we still have enough data points in every bucket + while (blocknum < 250) + mpool.removeForBlock(block, ++blocknum, dummyConflicted); + + for (int i = 1; i < 10; i++) + { + BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i - 1] + deltaFee); + BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i - 1] - deltaFee); + BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i - 1] + deltaPri); + BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i - 1] - deltaPri); + } + + + // Mine 15 more blocks with lots of transactions happening and not getting mined + // Estimates should go up + while (blocknum < 265) + { + for (int j = 0; j < 10; j++) + { // For each fee/pri multiple + for (int k = 0; k < 5; k++) + { // add 4 fee txs for every priority tx + tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k; + uint256 hash = tx.GetHash(); + mpool.addUnchecked(hash, entry.Fee(feeV[k / 4][j]) + .Time(GetTime()) + .Priority(priV[k / 4][j]) + .Height(blocknum) + .FromTx(tx, &mpool)); + txHashes[j].push_back(hash); + } + } + mpool.removeForBlock(block, ++blocknum, dummyConflicted); + } + + int answerFound; + for (int i = 1; i < 10; i++) + { + BOOST_CHECK( + mpool.estimateFee(i) == CFeeRate(0) || mpool.estimateFee(i).GetFeePerK() > origFeeEst[i - 1] - deltaFee); + BOOST_CHECK(mpool.estimateSmartFee(i, &answerFound).GetFeePerK() > origFeeEst[answerFound - 1] - deltaFee); + BOOST_CHECK(mpool.estimatePriority(i) == -1 || mpool.estimatePriority(i) > origPriEst[i - 1] - deltaPri); + BOOST_CHECK(mpool.estimateSmartPriority(i, &answerFound) > origPriEst[answerFound - 1] - deltaPri); + } + + // Mine all those transactions + // Estimates should still not be below original + for (int j = 0; j < 10; j++) + { + while (txHashes[j].size()) + { + CTransaction btx; + if (mpool.lookup(txHashes[j].back(), btx)) + block.push_back(btx); + txHashes[j].pop_back(); + } + } + mpool.removeForBlock(block, 265, dummyConflicted); + block.clear(); + for (int i = 1; i < 10; i++) + { + BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i - 1] - deltaFee); + BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i - 1] - deltaPri); + } + + // Mine 200 more blocks where everything is mined every block + // Estimates should be below original estimates + while (blocknum < 465) + { + for (int j = 0; j < 10; j++) + { // For each fee/pri multiple + for (int k = 0; k < 5; k++) + { // add 4 fee txs for every priority tx + tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k; + uint256 hash = tx.GetHash(); + mpool.addUnchecked(hash, entry.Fee(feeV[k / 4][j]) + .Time(GetTime()) + .Priority(priV[k / 4][j]) + .Height(blocknum) + .FromTx(tx, &mpool)); + CTransaction btx; + if (mpool.lookup(hash, btx)) + block.push_back(btx); + } + } + mpool.removeForBlock(block, ++blocknum, dummyConflicted); + block.clear(); + } + for (int i = 1; i < 10; i++) + { + BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i - 1] - deltaFee); + BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i - 1] - deltaPri); + } + + // Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee + // and that estimateSmartPriority returns essentially an infinite value + mpool.addUnchecked( + tx.GetHash(), entry.Fee(feeV[0][5]).Time(GetTime()).Priority(priV[1][5]).Height(blocknum).FromTx(tx, &mpool)); + // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[0][5] + mpool.TrimToSize(1); + BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[0][5]); + for (int i = 1; i < 10; i++) + { + BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.estimateFee(i).GetFeePerK()); + BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK()); + BOOST_CHECK(mpool.estimateSmartPriority(i) == INF_PRIORITY); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp new file mode 100644 index 00000000..30d829b0 --- /dev/null +++ b/src/test/pow_tests.cpp @@ -0,0 +1,361 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "pow.h" +#include "chain.h" +#include "chainparams.h" +#include "random.h" +#include "test/test_bitcoin.h" +#include "util.h" + +#include + +using namespace std; + +BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) + +/* Test calculation of next difficulty target with no constraints applying */ +BOOST_AUTO_TEST_CASE(get_next_work) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params ¶ms = Params().GetConsensus(); + + int64_t nLastRetargetTime = 1261130161; // Block #30240 + CBlockIndex pindexLast; + pindexLast.nHeight = 32255; + pindexLast.nTime = 1262152739; // Block #32255 + pindexLast.nBits = 0x1d00ffff; + BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00d86a); +} + +/* Test the constraint on the upper bound for next work */ +BOOST_AUTO_TEST_CASE(get_next_work_pow_limit) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params ¶ms = Params().GetConsensus(); + + int64_t nLastRetargetTime = 1231006505; // Block #0 + CBlockIndex pindexLast; + pindexLast.nHeight = 2015; + pindexLast.nTime = 1233061996; // Block #2015 + pindexLast.nBits = 0x1d00ffff; + BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00ffff); +} + +/* Test the constraint on the lower bound for actual time taken */ +BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params ¶ms = Params().GetConsensus(); + + int64_t nLastRetargetTime = 1279008237; // Block #66528 + CBlockIndex pindexLast; + pindexLast.nHeight = 68543; + pindexLast.nTime = 1279297671; // Block #68543 + pindexLast.nBits = 0x1c05a3f4; + BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1c0168fd); +} + +/* Test the constraint on the upper bound for actual time taken */ +BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params ¶ms = Params().GetConsensus(); + + int64_t nLastRetargetTime = 1263163443; // NOTE: Not an actual block time + CBlockIndex pindexLast; + pindexLast.nHeight = 46367; + pindexLast.nTime = 1269211443; // Block #46367 + pindexLast.nBits = 0x1c387f6f; + BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00e1fd); +} + +BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params ¶ms = Params().GetConsensus(); + + std::vector blocks(10000); + for (int i = 0; i < 10000; i++) + { + blocks[i].pprev = i ? &blocks[i - 1] : NULL; + blocks[i].nHeight = i; + blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing; + blocks[i].nBits = 0x207fffff; /* target 0x7fffff000... */ +#ifndef BITCOIN_CASH + blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); +#else + blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i]) : arith_uint256(0); +#endif + } + + for (int j = 0; j < 1000; j++) + { + CBlockIndex *p1 = &blocks[GetRand(10000)]; + CBlockIndex *p2 = &blocks[GetRand(10000)]; + CBlockIndex *p3 = &blocks[GetRand(10000)]; + + int64_t tdiff = GetBlockProofEquivalentTime(*p1, *p2, *p3, params); + BOOST_CHECK_EQUAL(tdiff, p1->GetBlockTime() - p2->GetBlockTime()); + } +} + +static CBlockIndex GetBlockIndex(CBlockIndex *pindexPrev, int64_t nTimeInterval, uint32_t nBits) +{ + CBlockIndex block; + block.pprev = pindexPrev; + block.nHeight = pindexPrev->nHeight + 1; + block.nTime = pindexPrev->nTime + nTimeInterval; + block.nBits = nBits; +#ifdef BITCOIN_CASH + block.nChainWork = pindexPrev->nChainWork + GetBlockProof(block); +#endif + return block; +} + +BOOST_AUTO_TEST_CASE(retargeting_test) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params ¶ms = Params().GetConsensus(); + + std::vector blocks(115); + + const arith_uint256 powLimit = UintToArith256(params.powLimit); + arith_uint256 currentPow = powLimit >> 1; + uint32_t initialBits = currentPow.GetCompact(); + + // Genesis block. + blocks[0] = CBlockIndex(); + blocks[0].nHeight = 0; + blocks[0].nTime = 1269211443; + blocks[0].nBits = initialBits; + +#ifdef BITCOIN_CASH + blocks[0].nChainWork = GetBlockProof(blocks[0]); +#endif + // Pile up some blocks. + for (size_t i = 1; i < 100; i++) + { + blocks[i] = GetBlockIndex(&blocks[i - 1], params.nPowTargetSpacing, initialBits); + } + + CBlockHeader blkHeaderDummy; + + // We start getting 2h blocks time. For the first 5 blocks, it doesn't + // matter as the MTP is not affected. For the next 5 block, MTP difference + // increases but stays below 12h. + for (size_t i = 100; i < 110; i++) + { + blocks[i] = GetBlockIndex(&blocks[i - 1], 2 * 3600, initialBits); + BOOST_CHECK_EQUAL(GetNextWorkRequired(&blocks[i], &blkHeaderDummy, params), initialBits); + } + + // Now we expect the difficulty to decrease. + blocks[110] = GetBlockIndex(&blocks[109], 2 * 3600, initialBits); + currentPow.SetCompact(currentPow.GetCompact()); + currentPow += (currentPow >> 2); + BOOST_CHECK_EQUAL(GetNextWorkRequired(&blocks[110], &blkHeaderDummy, params), currentPow.GetCompact()); + + // As we continue with 2h blocks, difficulty continue to decrease. + blocks[111] = GetBlockIndex(&blocks[110], 2 * 3600, currentPow.GetCompact()); + currentPow.SetCompact(currentPow.GetCompact()); + currentPow += (currentPow >> 2); + BOOST_CHECK_EQUAL(GetNextWorkRequired(&blocks[111], &blkHeaderDummy, params), currentPow.GetCompact()); + + // We decrease again. + blocks[112] = GetBlockIndex(&blocks[111], 2 * 3600, currentPow.GetCompact()); + currentPow.SetCompact(currentPow.GetCompact()); + currentPow += (currentPow >> 2); + BOOST_CHECK_EQUAL(GetNextWorkRequired(&blocks[112], &blkHeaderDummy, params), currentPow.GetCompact()); + + // We check that we do not go below the minimal difficulty. + blocks[113] = GetBlockIndex(&blocks[112], 2 * 3600, currentPow.GetCompact()); + currentPow.SetCompact(currentPow.GetCompact()); + currentPow += (currentPow >> 2); + BOOST_CHECK(powLimit.GetCompact() != currentPow.GetCompact()); + BOOST_CHECK_EQUAL(GetNextWorkRequired(&blocks[113], &blkHeaderDummy, params), powLimit.GetCompact()); + + // Once we reached the minimal difficulty, we stick with it. + blocks[114] = GetBlockIndex(&blocks[113], 2 * 3600, powLimit.GetCompact()); + BOOST_CHECK(powLimit.GetCompact() != currentPow.GetCompact()); + BOOST_CHECK_EQUAL(GetNextWorkRequired(&blocks[114], &blkHeaderDummy, params), powLimit.GetCompact()); +} + +#ifdef BITCOIN_CASH +BOOST_AUTO_TEST_CASE(cash_difficulty_test) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params ¶ms = Params().GetConsensus(); + + std::vector blocks(3000); + + const arith_uint256 powLimit = UintToArith256(params.powLimit); + uint32_t powLimitBits = powLimit.GetCompact(); + arith_uint256 currentPow = powLimit >> 4; + uint32_t initialBits = currentPow.GetCompact(); + + // Genesis block. + blocks[0] = CBlockIndex(); + blocks[0].nHeight = 0; + blocks[0].nTime = 1269211443; + blocks[0].nBits = initialBits; + + blocks[0].nChainWork = GetBlockProof(blocks[0]); + + // Block counter. + size_t i; + + // Pile up some blocks every 10 mins to establish some history. + for (i = 1; i < 2050; i++) + { + blocks[i] = GetBlockIndex(&blocks[i - 1], 600, initialBits); + } + + CBlockHeader blkHeaderDummy; + uint32_t nBits = GetNextCashWorkRequired(&blocks[2049], &blkHeaderDummy, params); + + // Difficulty stays the same as long as we produce a block every 10 mins. + for (size_t j = 0; j < 10; i++, j++) + { + blocks[i] = GetBlockIndex(&blocks[i - 1], 600, nBits); + BOOST_CHECK_EQUAL(GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params), nBits); + } + + // Make sure we skip over blocks that are out of wack. To do so, we produce + // a block that is far in the future, and then produce a block with the + // expected timestamp. + blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits); + BOOST_CHECK_EQUAL(GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, params), nBits); + blocks[i] = GetBlockIndex(&blocks[i - 1], 2 * 600 - 6000, nBits); + BOOST_CHECK_EQUAL(GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, params), nBits); + + // The system should continue unaffected by the block with a bogous + // timestamps. + for (size_t j = 0; j < 20; i++, j++) + { + blocks[i] = GetBlockIndex(&blocks[i - 1], 600, nBits); + BOOST_CHECK_EQUAL(GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params), nBits); + } + + // We start emitting blocks slightly faster. The first block has no impact. + blocks[i] = GetBlockIndex(&blocks[i - 1], 550, nBits); + BOOST_CHECK_EQUAL(GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, params), nBits); + + // Now we should see difficulty increase slowly. + for (size_t j = 0; j < 10; i++, j++) + { + blocks[i] = GetBlockIndex(&blocks[i - 1], 550, nBits); + const uint32_t nextBits = GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params); + + arith_uint256 currentTarget; + currentTarget.SetCompact(nBits); + arith_uint256 nextTarget; + nextTarget.SetCompact(nextBits); + + // Make sure that difficulty increases very slowly. + BOOST_CHECK(nextTarget < currentTarget); + BOOST_CHECK((currentTarget - nextTarget) < (currentTarget >> 10)); + + nBits = nextBits; + } + + // Check the actual value. + BOOST_CHECK_EQUAL(nBits, 0x1c0fe7b1); + + // If we dramatically shorten block production, difficulty increases faster. + for (size_t j = 0; j < 20; i++, j++) + { + blocks[i] = GetBlockIndex(&blocks[i - 1], 10, nBits); + const uint32_t nextBits = GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params); + + arith_uint256 currentTarget; + currentTarget.SetCompact(nBits); + arith_uint256 nextTarget; + nextTarget.SetCompact(nextBits); + + // Make sure that difficulty increases faster. + BOOST_CHECK(nextTarget < currentTarget); + BOOST_CHECK((currentTarget - nextTarget) < (currentTarget >> 4)); + + nBits = nextBits; + } + + // Check the actual value. + BOOST_CHECK_EQUAL(nBits, 0x1c0db19f); + + // We start to emit blocks significantly slower. The first block has no + // impact. + blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits); + nBits = GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, params); + + // Check the actual value. + BOOST_CHECK_EQUAL(nBits, 0x1c0d9222); + + // If we dramatically slow down block production, difficulty decreases. + for (size_t j = 0; j < 93; i++, j++) + { + blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits); + const uint32_t nextBits = GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params); + + arith_uint256 currentTarget; + currentTarget.SetCompact(nBits); + arith_uint256 nextTarget; + nextTarget.SetCompact(nextBits); + + // Check the difficulty decreases. + BOOST_CHECK(nextTarget <= powLimit); + BOOST_CHECK(nextTarget > currentTarget); + BOOST_CHECK((nextTarget - currentTarget) < (currentTarget >> 3)); + + nBits = nextBits; + } + + // Check the actual value. + BOOST_CHECK_EQUAL(nBits, 0x1c2f13b9); + + // Due to the window of time being bounded, next block's difficulty actually + // gets harder. + blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits); + nBits = GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, params); + BOOST_CHECK_EQUAL(nBits, 0x1c2ee9bf); + + // And goes down again. It takes a while due to the window being bounded and + // the skewed block causes 2 blocks to get out of the window. + for (size_t j = 0; j < 192; i++, j++) + { + blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits); + const uint32_t nextBits = GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params); + + arith_uint256 currentTarget; + currentTarget.SetCompact(nBits); + arith_uint256 nextTarget; + nextTarget.SetCompact(nextBits); + + // Check the difficulty decreases. + BOOST_CHECK(nextTarget <= powLimit); + BOOST_CHECK(nextTarget > currentTarget); + BOOST_CHECK((nextTarget - currentTarget) < (currentTarget >> 3)); + + nBits = nextBits; + } + + // Check the actual value. + BOOST_CHECK_EQUAL(nBits, 0x1d00ffff); + + // Once the difficulty reached the minimum allowed level, it doesn't get any + // easier. + for (size_t j = 0; j < 5; i++, j++) + { + blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits); + const uint32_t nextBits = GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params); + + // Check the difficulty stays constant. + BOOST_CHECK_EQUAL(nextBits, powLimitBits); + nBits = nextBits; + } +} +#endif + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp new file mode 100644 index 00000000..951bf85a --- /dev/null +++ b/src/test/prevector_tests.cpp @@ -0,0 +1,259 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "prevector.h" +#include "random.h" +#include + +#include "serialize.h" +#include "streams.h" + +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(prevector_tests, TestingSetup) // BU harmonize suite name with filename + +template +class prevector_tester +{ + typedef std::vector realtype; + realtype real_vector; + + typedef prevector pretype; + pretype pre_vector; + + typedef typename pretype::size_type Size; + + void test() + { + const pretype &const_pre_vector = pre_vector; + BOOST_CHECK_EQUAL(real_vector.size(), pre_vector.size()); + BOOST_CHECK_EQUAL(real_vector.empty(), pre_vector.empty()); + for (Size s = 0; s < real_vector.size(); s++) + { + if (real_vector[s] != pre_vector[s]) + BOOST_CHECK(real_vector[s] == pre_vector[s]); + if (&(pre_vector[s]) != &(pre_vector.begin()[s])) + BOOST_CHECK(&(pre_vector[s]) == &(pre_vector.begin()[s])); + if (&(pre_vector[s]) != &*(pre_vector.begin() + s)) + BOOST_CHECK(&(pre_vector[s]) == &*(pre_vector.begin() + s)); + if (&(pre_vector[s]) != &*((pre_vector.end() + s) - real_vector.size())) + BOOST_CHECK(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size())); + } + // BOOST_CHECK(realtype(pre_vector) == real_vector); + BOOST_CHECK(pretype(real_vector.begin(), real_vector.end()) == pre_vector); + BOOST_CHECK(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector); + size_t pos = 0; + BOOST_FOREACH (const T &v, pre_vector) + { + if (v != real_vector[pos++]) + BOOST_CHECK(v == real_vector[pos++]); + } + BOOST_REVERSE_FOREACH (const T &v, pre_vector) + { + if (v != real_vector[--pos]) + BOOST_CHECK(v == real_vector[--pos]); + } + BOOST_FOREACH (const T &v, const_pre_vector) + { + if (v != real_vector[pos++]) + BOOST_CHECK(v == real_vector[pos++]); + } + BOOST_REVERSE_FOREACH (const T &v, const_pre_vector) + { + if (v != real_vector[--pos]) + BOOST_CHECK(v == real_vector[--pos]); + } + CDataStream ss1(SER_DISK, 0); + CDataStream ss2(SER_DISK, 0); + ss1 << real_vector; + ss2 << pre_vector; + BOOST_CHECK_EQUAL(ss1.size(), ss2.size()); + for (Size s = 0; s < ss1.size(); s++) + { + if (ss1[s] != ss2[s]) + BOOST_CHECK_EQUAL(ss1[s], ss2[s]); + } + } + +public: + void resize(Size s) + { + real_vector.resize(s); + BOOST_CHECK_EQUAL(real_vector.size(), s); + pre_vector.resize(s); + BOOST_CHECK_EQUAL(pre_vector.size(), s); + test(); + } + + void reserve(Size s) + { + real_vector.reserve(s); + BOOST_CHECK(real_vector.capacity() >= s); + pre_vector.reserve(s); + BOOST_CHECK(pre_vector.capacity() >= s); + test(); + } + + void insert(Size position, const T &value) + { + real_vector.insert(real_vector.begin() + position, value); + pre_vector.insert(pre_vector.begin() + position, value); + test(); + } + + void insert(Size position, Size count, const T &value) + { + real_vector.insert(real_vector.begin() + position, count, value); + pre_vector.insert(pre_vector.begin() + position, count, value); + test(); + } + + template + void insert_range(Size position, I first, I last) + { + real_vector.insert(real_vector.begin() + position, first, last); + pre_vector.insert(pre_vector.begin() + position, first, last); + test(); + } + + void erase(Size position) + { + real_vector.erase(real_vector.begin() + position); + pre_vector.erase(pre_vector.begin() + position); + test(); + } + + void erase(Size first, Size last) + { + real_vector.erase(real_vector.begin() + first, real_vector.begin() + last); + pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last); + test(); + } + + void update(Size pos, const T &value) + { + real_vector[pos] = value; + pre_vector[pos] = value; + test(); + } + + void push_back(const T &value) + { + real_vector.push_back(value); + pre_vector.push_back(value); + test(); + } + + void pop_back() + { + real_vector.pop_back(); + pre_vector.pop_back(); + test(); + } + + void clear() + { + real_vector.clear(); + pre_vector.clear(); + } + + void assign(Size n, const T &value) + { + real_vector.assign(n, value); + pre_vector.assign(n, value); + } + + Size size() { return real_vector.size(); } + Size capacity() { return pre_vector.capacity(); } + void shrink_to_fit() + { + pre_vector.shrink_to_fit(); + test(); + } +}; + +BOOST_AUTO_TEST_CASE(PrevectorTestInt) +{ + for (int j = 0; j < 64; j++) + { + prevector_tester<8, int> test; + for (int i = 0; i < 2048; i++) + { + int r = insecure_rand(); + if ((r % 4) == 0) + { + test.insert(insecure_rand() % (test.size() + 1), insecure_rand()); + } + if (test.size() > 0 && ((r >> 2) % 4) == 1) + { + test.erase(insecure_rand() % test.size()); + } + if (((r >> 4) % 8) == 2) + { + int new_size = std::max(0, std::min(30, test.size() + (insecure_rand() % 5) - 2)); + test.resize(new_size); + } + if (((r >> 7) % 8) == 3) + { + test.insert(insecure_rand() % (test.size() + 1), 1 + (insecure_rand() % 2), insecure_rand()); + } + if (((r >> 10) % 8) == 4) + { + int del = std::min(test.size(), 1 + (insecure_rand() % 2)); + int beg = insecure_rand() % (test.size() + 1 - del); + test.erase(beg, beg + del); + } + if (((r >> 13) % 16) == 5) + { + test.push_back(insecure_rand()); + } + if (test.size() > 0 && ((r >> 17) % 16) == 6) + { + test.pop_back(); + } + if (((r >> 21) % 32) == 7) + { + int values[4]; + int num = 1 + (insecure_rand() % 4); + for (int i = 0; i < num; i++) + { + values[i] = insecure_rand(); + } + test.insert_range(insecure_rand() % (test.size() + 1), values, values + num); + } + if (((r >> 26) % 32) == 8) + { + int del = std::min(test.size(), 1 + (insecure_rand() % 4)); + int beg = insecure_rand() % (test.size() + 1 - del); + test.erase(beg, beg + del); + } + r = insecure_rand(); + if (r % 32 == 9) + { + test.reserve(insecure_rand() % 32); + } + if ((r >> 5) % 64 == 10) + { + test.shrink_to_fit(); + } + if (test.size() > 0) + { + test.update(insecure_rand() % test.size(), insecure_rand()); + } + if (((r >> 11) & 1024) == 11) + { + test.clear(); + } + if (((r >> 21) & 512) == 12) + { + test.assign(insecure_rand() % 32, insecure_rand()); + } + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp new file mode 100644 index 00000000..59034885 --- /dev/null +++ b/src/test/reverselock_tests.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "reverselock.h" +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(reverselock_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(reverselock_basics) +{ + boost::mutex mutex; + boost::unique_lock lock(mutex); + + BOOST_CHECK(lock.owns_lock()); + { + reverse_lock > rlock(lock); + BOOST_CHECK(!lock.owns_lock()); + } + BOOST_CHECK(lock.owns_lock()); +} + +BOOST_AUTO_TEST_CASE(reverselock_errors) +{ + boost::mutex mutex; + boost::unique_lock lock(mutex); + + // Make sure trying to reverse lock an unlocked lock fails + lock.unlock(); + + BOOST_CHECK(!lock.owns_lock()); + + bool failed = false; + try + { + reverse_lock > rlock(lock); + } + catch (...) + { + failed = true; + } + + BOOST_CHECK(failed); + BOOST_CHECK(!lock.owns_lock()); + + // Locking the original lock after it has been taken by a reverse lock + // makes no sense. Ensure that the original lock no longer owns the lock + // after giving it to a reverse one. + + lock.lock(); + BOOST_CHECK(lock.owns_lock()); + { + reverse_lock > rlock(lock); + BOOST_CHECK(!lock.owns_lock()); + } + + BOOST_CHECK(failed); + BOOST_CHECK(lock.owns_lock()); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 06e71a6b..eb838226 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -1,61 +1,409 @@ -#include +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "rpc/client.h" +#include "rpc/server.h" #include "base58.h" -#include "util.h" -#include "bitcoinrpc.h" +#include "net.h" +#include "netbase.h" +#include "unlimited.h" -using namespace std; -using namespace json_spirit; +#include "test/test_bitcoin.h" + +#include +#include +#include -BOOST_AUTO_TEST_SUITE(rpc_tests) +#include -static Array -createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL) +using namespace std; + +UniValue createArgs(int nRequired, const char *address1 = NULL, const char *address2 = NULL) { - Array result; + UniValue result(UniValue::VARR); result.push_back(nRequired); - Array addresses; - if (address1) addresses.push_back(address1); - if (address2) addresses.push_back(address2); + UniValue addresses(UniValue::VARR); + if (address1) + addresses.push_back(address1); + if (address2) + addresses.push_back(address2); result.push_back(addresses); return result; } -BOOST_AUTO_TEST_CASE(rpc_addmultisig) +UniValue CallRPC(string args) +{ + vector vArgs; + boost::split(vArgs, args, boost::is_any_of(" \t")); + string strMethod = vArgs[0]; + vArgs.erase(vArgs.begin()); + UniValue params = RPCConvertValues(strMethod, vArgs); + // calling boost_check here sets the last checkpoint to a useless position + if (!tableRPC[strMethod]) + BOOST_CHECK(tableRPC[strMethod]); + rpcfn_type method = tableRPC[strMethod]->actor; + try + { + UniValue result = (*method)(params, false); + return result; + } + catch (const UniValue &objError) + { + throw runtime_error(find_value(objError, "message").get_str()); + } +} + + +BOOST_FIXTURE_TEST_SUITE(rpc_tests, TestingSetup) + +BOOST_AUTO_TEST_CASE(rpc_rawparams) +{ + // Test raw transaction API argument handling + UniValue r; + + BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error); + BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error); + BOOST_CHECK_THROW( + CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), + runtime_error); + + BOOST_CHECK_THROW(CallRPC("createrawtransaction"), runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction [] []"), runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction {} {}"), runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [] {}")); + BOOST_CHECK_THROW(CallRPC("createrawtransaction [] {} extra"), runtime_error); + + BOOST_CHECK_THROW(CallRPC("decoderawtransaction"), runtime_error); + BOOST_CHECK_THROW(CallRPC("decoderawtransaction null"), runtime_error); + BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), runtime_error); + string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93" + "bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b06" + "9a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447" + "c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"; + BOOST_CHECK_NO_THROW(r = CallRPC(string("decoderawtransaction ") + rawtx)); + BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").get_int(), 193); + BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1); + BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0); + BOOST_CHECK_THROW(r = CallRPC(string("decoderawtransaction ") + rawtx + " extra"), runtime_error); + + BOOST_CHECK_THROW(CallRPC("signrawtransaction"), runtime_error); + BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), runtime_error); + BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), runtime_error); + BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ") + rawtx)); + BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ") + rawtx + " null null NONE|ANYONECANPAY")); + BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ") + rawtx + " [] [] NONE|ANYONECANPAY")); + BOOST_CHECK_THROW(CallRPC(string("signrawtransaction ") + rawtx + " null null badenum"), runtime_error); + + // Only check failure cases for sendrawtransaction, there's no network to send to... + BOOST_CHECK_THROW(CallRPC("sendrawtransaction"), runtime_error); + BOOST_CHECK_THROW(CallRPC("sendrawtransaction null"), runtime_error); + BOOST_CHECK_THROW(CallRPC("sendrawtransaction DEADBEEF"), runtime_error); + BOOST_CHECK_THROW(CallRPC(string("sendrawtransaction ") + rawtx + " extra"), runtime_error); +} + +BOOST_AUTO_TEST_CASE(rpc_rawsign) +{ + UniValue r; + // input is a 1-of-2 multisig (so is output): + string prevout = "[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\"," + "\"vout\":1,\"scriptPubKey\":\"a914b10c9df5f7edf436c697f02f1efdba4cf399615187\"," + "\"redeemScript\":" + "\"512103debedc17b3df2badbcdd86d5feb4562b86fe182e5998abd8bcd4f122c6155b1b21027e940bb73ab8732bfdf7f" + "9216ecefca5b94d6df834e77e108f68e66f126044c052ae\"," + "\"amount\":3.14159" + "}]"; + r = CallRPC(string("createrawtransaction ") + prevout + " " + "{\"3HqAe9LtNBjnsfM4CyYaWTnvCaUYT7v4oZ\":11}"); + string notsigned = r.get_str(); + string privkey1 = "\"KzsXybp9jX64P5ekX1KUxRQ79Jht9uzW7LorgwE65i5rWACL6LQe\""; + string privkey2 = "\"Kyhdf5LuKTRx4ge69ybABsiUAWjVRK4XGxAKk2FQLp2HjGMy87Z4\""; + r = CallRPC(string("signrawtransaction ") + notsigned + " " + prevout + " " + "[]"); + BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false); + r = CallRPC( + string("signrawtransaction ") + notsigned + " " + prevout + " " + "[" + privkey1 + "," + privkey2 + "]"); + BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true); +} + +BOOST_AUTO_TEST_CASE(rpc_createraw_op_return) +{ + BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction " + "[{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\"," + "\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\"}")); + + // Allow more than one data transaction output + BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction " + "[{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\"," + "\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\",\"data\":\"68656c6c6f776f726c64\"}")); + + // Key not "data" (bad address) + BOOST_CHECK_THROW(CallRPC("createrawtransaction " + "[{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\"," + "\"vout\":0}] {\"somedata\":\"68656c6c6f776f726c64\"}"), + runtime_error); + + // Bad hex encoding of data output + BOOST_CHECK_THROW(CallRPC("createrawtransaction " + "[{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\"," + "\"vout\":0}] {\"data\":\"12345\"}"), + runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction " + "[{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\"," + "\"vout\":0}] {\"data\":\"12345g\"}"), + runtime_error); + + // Data 81 bytes long + BOOST_CHECK_NO_THROW( + CallRPC("createrawtransaction " + "[{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] " + "{\"data\":" + "\"0102030405060708091011121314151617181920212223242526272829303132333435363738394041424344454647484950" + "51525354555657585960616263646566676869707172737475767778798081\"}")); +} + +BOOST_AUTO_TEST_CASE(rpc_format_monetary_values) +{ + BOOST_CHECK(ValueFromAmount(0LL).write() == "0.00000000"); + BOOST_CHECK(ValueFromAmount(1LL).write() == "0.00000001"); + BOOST_CHECK(ValueFromAmount(17622195LL).write() == "0.17622195"); + BOOST_CHECK(ValueFromAmount(50000000LL).write() == "0.50000000"); + BOOST_CHECK(ValueFromAmount(89898989LL).write() == "0.89898989"); + BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000"); + BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990"); + BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999"); + + BOOST_CHECK_EQUAL(ValueFromAmount(0).write(), "0.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount((COIN / 10000) * 123456789).write(), "12345.67890000"); + BOOST_CHECK_EQUAL(ValueFromAmount(-COIN).write(), "-1.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(-COIN / 10).write(), "-0.10000000"); + + BOOST_CHECK_EQUAL(ValueFromAmount(COIN * 100000000).write(), "100000000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN * 10000000).write(), "10000000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN * 1000000).write(), "1000000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN * 100000).write(), "100000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN * 10000).write(), "10000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN * 1000).write(), "1000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN * 100).write(), "100.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN * 10).write(), "10.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN).write(), "1.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN / 10).write(), "0.10000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN / 100).write(), "0.01000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN / 1000).write(), "0.00100000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN / 10000).write(), "0.00010000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN / 100000).write(), "0.00001000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN / 1000000).write(), "0.00000100"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN / 10000000).write(), "0.00000010"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN / 100000000).write(), "0.00000001"); +} + +static UniValue ValueFromString(const std::string &str) +{ + UniValue value; + BOOST_CHECK(value.setNumStr(str)); + return value; +} + +BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values) { - rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor; + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("-0.00000001")), UniValue); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0")), 0LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000000")), 0LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001")), 1LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.17622195")), 17622195LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.5")), 50000000LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.50000000")), 50000000LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.89898989")), 89898989LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1.00000000")), 100000000LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.9999999")), 2099999999999990LL); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.99999999")), 2099999999999999LL); + + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1e-8")), COIN / 100000000); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.1e-7")), COIN / 100000000); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.01e-6")), COIN / 100000000); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString( + "0.0000000000000000000000000000000000000000000000000000000000000000000000000001e+68")), + COIN / 100000000); + BOOST_CHECK_EQUAL( + AmountFromValue(ValueFromString("10000000000000000000000000000000000000000000000000000000000000000e-64")), + COIN); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0." + "0000000000000000000000000000000000000000000000000000000000000001" + "00000000000000000000000000000000000000000000000000000e64")), + COIN); + + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e-9")), UniValue); // should fail + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("0.000000019")), UniValue); // should fail + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001000000")), 1LL); // should pass, cut trailing 0 + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("19e-9")), UniValue); // should fail + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.19e-6")), 19); // should pass, leading 0 is present + + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("92233720368.54775808")), UniValue); // overflow error + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e+11")), UniValue); // overflow error + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e11")), UniValue); // overflow error signless + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("93e+9")), UniValue); // overflow error +} + +BOOST_AUTO_TEST_CASE(json_parse_errors) +{ + // Valid + BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0").get_real(), 1.0); + // Valid, with leading or trailing whitespace + BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0); + BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0); + + // should fail, missing leading 0, therefore invalid JSON + BOOST_CHECK_THROW(AmountFromValue(ParseNonRFCJSONValue(".19e-6")), std::runtime_error); + BOOST_CHECK_EQUAL(AmountFromValue(ParseNonRFCJSONValue("0.00000000000000000000000000000000000001e+30 ")), 1); + // Invalid, initial garbage + BOOST_CHECK_THROW(ParseNonRFCJSONValue("[1.0"), std::runtime_error); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("a1.0"), std::runtime_error); + // Invalid, trailing garbage + BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0sds"), std::runtime_error); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0]"), std::runtime_error); + // BTC addresses should fail parsing + BOOST_CHECK_THROW(ParseNonRFCJSONValue("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), std::runtime_error); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(rpc_ban) +{ + BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); + + UniValue r; + BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0 add"))); + // portnumber for setban not allowed + BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.0:8334")), runtime_error); + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + UniValue ar = r.get_array(); + UniValue o1 = ar[0].get_obj(); + UniValue adr = find_value(o1, "address"); + BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/32"); + BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0 remove"))); + ; + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + BOOST_CHECK_EQUAL(ar.size(), 0); + + BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 1607731200 true"))); + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + o1 = ar[0].get_obj(); + adr = find_value(o1, "address"); + UniValue banned_until = find_value(o1, "banned_until"); + BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); + BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check - // old, 65-byte-long: - const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8"; - // new, compressed: - const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4"; + BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); - Value v; - CBitcoinAddress address; - BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false)); - address.SetString(v.get_str()); - BOOST_CHECK(address.IsValid() && address.IsScript()); + BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 200"))); + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + o1 = ar[0].get_obj(); + adr = find_value(o1, "address"); + banned_until = find_value(o1, "banned_until"); + BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); + int64_t now = GetTime(); + BOOST_CHECK(banned_until.get_int64() > now); + BOOST_CHECK(banned_until.get_int64() - now <= 200); - BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false)); - address.SetString(v.get_str()); - BOOST_CHECK(address.IsValid() && address.IsScript()); + // must throw an exception because 127.0.0.1 is in already banned suubnet range + BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.1 add")), runtime_error); - BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false)); - address.SetString(v.get_str()); - BOOST_CHECK(address.IsValid() && address.IsScript()); + BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0/24 remove"))); + ; + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + BOOST_CHECK_EQUAL(ar.size(), 0); + + BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/255.255.0.0 add"))); + BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.1.1 add")), runtime_error); + + BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + BOOST_CHECK_EQUAL(ar.size(), 0); + + + BOOST_CHECK_THROW(r = CallRPC(string("setban test add")), runtime_error); // invalid IP + + // IPv6 tests + BOOST_CHECK_NO_THROW(r = CallRPC(string("setban FE80:0000:0000:0000:0202:B3FF:FE1E:8329 add"))); + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + o1 = ar[0].get_obj(); + adr = find_value(o1, "address"); + BOOST_CHECK_EQUAL(adr.get_str(), "fe80::202:b3ff:fe1e:8329/128"); + + BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:db8::/ffff:fffc:0:0:0:0:0:0 add"))); + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + o1 = ar[0].get_obj(); + adr = find_value(o1, "address"); + BOOST_CHECK_EQUAL(adr.get_str(), "2001:db8::/30"); + + BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128 add"))); + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + o1 = ar[0].get_obj(); + adr = find_value(o1, "address"); + BOOST_CHECK_EQUAL(adr.get_str(), "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128"); +} + +BOOST_AUTO_TEST_CASE(findlikelynode) +{ + CAddress addr1(CService("169.254.1.2")); + CNode n1(INVALID_SOCKET, addr1, "", true); + CAddress addr2(CService("169.254.2.3")); + CNode n2(INVALID_SOCKET, addr2, "", true); + assert(vNodes.size() == 0); + vNodes.push_back(&n1); + vNodes.push_back(&n2); + + // Test prefix matching + BOOST_CHECK(FindLikelyNode("169.254.1.2").get() == &n1); + BOOST_CHECK(FindLikelyNode("169.254.1.2:1234").get() == NULL); + BOOST_CHECK(FindLikelyNode("169.254.1").get() == &n1); + + // Test wildcard matching + BOOST_CHECK(FindLikelyNode("169.254.1*").get() == &n1); + BOOST_CHECK(FindLikelyNode("169.254.2*").get() == &n2); + BOOST_CHECK(FindLikelyNode("169.254.2.3*").get() == &n2); + BOOST_CHECK(FindLikelyNode("169.254.2.?:?").get() == &n2); + BOOST_CHECK(FindLikelyNode("169.254.1.?:*").get() == &n1); + + vNodes.clear(); +} + +BOOST_AUTO_TEST_CASE(rpc_convert_values_generatetoaddress) +{ + UniValue result; - BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error); - BOOST_CHECK_THROW(addmultisig(createArgs(1), false), runtime_error); - BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), runtime_error); + BOOST_CHECK_NO_THROW(result = RPCConvertValues( + "generatetoaddress", boost::assign::list_of("101")("mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a"))); + BOOST_CHECK_EQUAL(result[0].get_int(), 101); + BOOST_CHECK_EQUAL(result[1].get_str(), "mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a"); - BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error); - BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error); + BOOST_CHECK_NO_THROW(result = RPCConvertValues( + "generatetoaddress", boost::assign::list_of("101")("mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU"))); + BOOST_CHECK_EQUAL(result[0].get_int(), 101); + BOOST_CHECK_EQUAL(result[1].get_str(), "mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU"); - string short1(address1Hex, address1Hex+sizeof(address1Hex)-2); // last byte missing - BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error); + BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", + boost::assign::list_of("1")("mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a")("9"))); + BOOST_CHECK_EQUAL(result[0].get_int(), 1); + BOOST_CHECK_EQUAL(result[1].get_str(), "mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a"); + BOOST_CHECK_EQUAL(result[2].get_int(), 9); - string short2(address1Hex+1, address1Hex+sizeof(address1Hex)); // first byte missing - BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error); + BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", + boost::assign::list_of("1")("mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU")("9"))); + BOOST_CHECK_EQUAL(result[0].get_int(), 1); + BOOST_CHECK_EQUAL(result[1].get_str(), "mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU"); + BOOST_CHECK_EQUAL(result[2].get_int(), 9); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp new file mode 100644 index 00000000..de958bb2 --- /dev/null +++ b/src/test/sanity_tests.cpp @@ -0,0 +1,21 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "compat/sanity.h" +#include "key.h" +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(sanity_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(basic_sanity) +{ + BOOST_CHECK_MESSAGE(glibc_sanity_test() == true, "libc sanity test"); + BOOST_CHECK_MESSAGE(glibcxx_sanity_test() == true, "stdlib sanity test"); + BOOST_CHECK_MESSAGE(ECC_InitSanityCheck() == true, "openssl ECC test"); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp new file mode 100644 index 00000000..97d366d5 --- /dev/null +++ b/src/test/scheduler_tests.cpp @@ -0,0 +1,127 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "scheduler.h" +#include "random.h" + +#include "test/test_bitcoin.h" + +#include +#include +#include +#include +#include + +BOOST_AUTO_TEST_SUITE(scheduler_tests) + +static void microTask(CScheduler &s, + boost::mutex &mutex, + int &counter, + int delta, + boost::chrono::system_clock::time_point rescheduleTime) +{ + { + boost::unique_lock lock(mutex); + counter += delta; + } + boost::chrono::system_clock::time_point noTime = boost::chrono::system_clock::time_point::min(); + if (rescheduleTime != noTime) + { + CScheduler::Function f = + boost::bind(µTask, boost::ref(s), boost::ref(mutex), boost::ref(counter), -delta + 1, noTime); + s.schedule(f, rescheduleTime); + } +} + +static void MicroSleep(uint64_t n) +{ +#if defined(HAVE_WORKING_BOOST_SLEEP_FOR) + boost::this_thread::sleep_for(boost::chrono::microseconds(n)); +#elif defined(HAVE_WORKING_BOOST_SLEEP) + boost::this_thread::sleep(boost::posix_time::microseconds(n)); +#else +// should never get here +#error missing boost sleep implementation +#endif +} + +BOOST_AUTO_TEST_CASE(manythreads) +{ + seed_insecure_rand(false); + + // Stress test: hundreds of microsecond-scheduled tasks, + // serviced by 10 threads. + // + // So... ten shared counters, which if all the tasks execute + // properly will sum to the number of tasks done. + // Each task adds or subtracts from one of the counters a + // random amount, and then schedules another task 0-1000 + // microseconds in the future to subtract or add from + // the counter -random_amount+1, so in the end the shared + // counters should sum to the number of initial tasks performed. + CScheduler microTasks; + + boost::mutex counterMutex[10]; + int counter[10] = {0}; + boost::random::mt19937 rng(insecure_rand()); + boost::random::uniform_int_distribution<> zeroToNine(0, 9); + boost::random::uniform_int_distribution<> randomMsec(-11, 1000); + boost::random::uniform_int_distribution<> randomDelta(-1000, 1000); + + boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now(); + boost::chrono::system_clock::time_point now = start; + boost::chrono::system_clock::time_point first, last; + size_t nTasks = microTasks.getQueueInfo(first, last); + BOOST_CHECK(nTasks == 0); + + for (int i = 0; i < 100; i++) + { + boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng)); + boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng)); + int whichCounter = zeroToNine(rng); + CScheduler::Function f = boost::bind(µTask, boost::ref(microTasks), boost::ref(counterMutex[whichCounter]), + boost::ref(counter[whichCounter]), randomDelta(rng), tReschedule); + microTasks.schedule(f, t); + } + nTasks = microTasks.getQueueInfo(first, last); + BOOST_CHECK(nTasks == 100); + BOOST_CHECK(first < last); + BOOST_CHECK(last > now); + + // As soon as these are created they will start running and servicing the queue + boost::thread_group microThreads; + for (int i = 0; i < 5; i++) + microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, µTasks)); + + MicroSleep(600); + now = boost::chrono::system_clock::now(); + + // More threads and more tasks: + for (int i = 0; i < 5; i++) + microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, µTasks)); + for (int i = 0; i < 100; i++) + { + boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng)); + boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng)); + int whichCounter = zeroToNine(rng); + CScheduler::Function f = boost::bind(µTask, boost::ref(microTasks), boost::ref(counterMutex[whichCounter]), + boost::ref(counter[whichCounter]), randomDelta(rng), tReschedule); + microTasks.schedule(f, t); + } + + // Drain the task queue then exit threads + microTasks.stop(true); + microThreads.join_all(); // ... wait until all the threads are done + + int counterSum = 0; + for (int i = 0; i < 10; i++) + { + BOOST_CHECK(counter[i] != 0); + counterSum += counter[i]; + } + BOOST_CHECK_EQUAL(counterSum, 200); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 96f895ac..460d51de 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -1,37 +1,39 @@ -#include -#include -#include -#include -#include +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "script/script.h" +#include "key.h" +#include "keystore.h" +#include "parallel.h" +#include "policy/policy.h" +#include "script/ismine.h" +#include "script/script_error.h" +#include "script/sign.h" +#include "test/test_bitcoin.h" + +#include -#include "../main.h" -#include "../script.h" -#include "../wallet.h" +#include using namespace std; -// Test routines internal to script.cpp: -extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); -extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, int nHashType); - // Helpers: -static std::vector -Serialize(const CScript& s) +static std::vector Serialize(const CScript &s) { - std::vector sSerialized(s); + std::vector sSerialized(s.begin(), s.end()); return sSerialized; } -static bool -Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict) +static bool Verify(const CScript &scriptSig, const CScript &scriptPubKey, bool fStrict, ScriptError &err) { // Create dummy to/from transactions: - CTransaction txFrom; + CMutableTransaction txFrom; txFrom.vout.resize(1); txFrom.vout[0].scriptPubKey = scriptPubKey; - CTransaction txTo; + CMutableTransaction txTo; txTo.vin.resize(1); txTo.vout.resize(1); txTo.vin[0].prevout.n = 0; @@ -39,14 +41,16 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict) txTo.vin[0].scriptSig = scriptSig; txTo.vout[0].nValue = 1; - return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict, 0); + return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, + MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), &err); } -BOOST_AUTO_TEST_SUITE(script_P2SH_tests) +BOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sign) { + LOCK(cs_main); // Pay-to-script-hash looks like this: // scriptSig: // scriptPubKey: HASH160 EQUAL @@ -63,27 +67,30 @@ BOOST_AUTO_TEST_CASE(sign) // 8 Scripts: checking all combinations of // different keys, straight/P2SH, pubkey/pubkeyhash CScript standardScripts[4]; - standardScripts[0] << key[0].GetPubKey() << OP_CHECKSIG; - standardScripts[1].SetDestination(key[1].GetPubKey().GetID()); - standardScripts[2] << key[1].GetPubKey() << OP_CHECKSIG; - standardScripts[3].SetDestination(key[2].GetPubKey().GetID()); + standardScripts[0] << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; + standardScripts[1] = GetScriptForDestination(key[1].GetPubKey().GetID()); + standardScripts[2] << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; + standardScripts[3] = GetScriptForDestination(key[2].GetPubKey().GetID()); CScript evalScripts[4]; for (int i = 0; i < 4; i++) { keystore.AddCScript(standardScripts[i]); - evalScripts[i].SetDestination(standardScripts[i].GetID()); + evalScripts[i] = GetScriptForDestination(CScriptID(standardScripts[i])); } - CTransaction txFrom; // Funding transaction: + CMutableTransaction txFrom; // Funding transaction: + string reason; txFrom.vout.resize(8); for (int i = 0; i < 4; i++) { txFrom.vout[i].scriptPubKey = evalScripts[i]; - txFrom.vout[i+4].scriptPubKey = standardScripts[i]; + txFrom.vout[i].nValue = COIN; + txFrom.vout[i + 4].scriptPubKey = standardScripts[i]; + txFrom.vout[i + 4].nValue = COIN; } - BOOST_CHECK(txFrom.IsStandard()); + BOOST_CHECK(IsStandardTx(txFrom, reason)); - CTransaction txTo[8]; // Spending transactions + CMutableTransaction txTo[8]; // Spending transactions for (int i = 0; i < 8; i++) { txTo[i].vin.resize(1); @@ -91,7 +98,9 @@ BOOST_AUTO_TEST_CASE(sign) txTo[i].vin[0].prevout.n = i; txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vout[0].nValue = 1; - BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); +#ifdef ENABLE_WALLET + BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey, 0), strprintf("IsMine %d", i)); +#endif } for (int i = 0; i < 8; i++) { @@ -104,7 +113,15 @@ BOOST_AUTO_TEST_CASE(sign) { CScript sigSave = txTo[i].vin[0].scriptSig; txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; - bool sigOK = VerifySignature(txFrom, txTo[i], 0, true, 0); + + const CTxOut &output = txFrom.vout[txTo[i].vin[0].prevout.n]; +#ifdef BITCOIN_CASH + bool sigOK = CScriptCheck(nullptr, output.scriptPubKey, output.nValue, txTo[i], 0, + SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID, false)(); +#else + bool sigOK = CScriptCheck(nullptr, output.scriptPubKey, output.nValue, txTo[i], 0, + SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false)(); +#endif if (i == j) BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); else @@ -115,79 +132,85 @@ BOOST_AUTO_TEST_CASE(sign) BOOST_AUTO_TEST_CASE(norecurse) { + ScriptError err; // Make sure only the outer pay-to-script-hash does the // extra-validation thing: CScript invalidAsScript; invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE; - CScript p2sh; - p2sh.SetDestination(invalidAsScript.GetID()); + CScript p2sh = GetScriptForDestination(CScriptID(invalidAsScript)); CScript scriptSig; scriptSig << Serialize(invalidAsScript); // Should not verify, because it will try to execute OP_INVALIDOPCODE - BOOST_CHECK(!Verify(scriptSig, p2sh, true)); + BOOST_CHECK(!Verify(scriptSig, p2sh, true, err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_BAD_OPCODE, ScriptErrorString(err)); // Try to recur, and verification should succeed because // the inner HASH160 <> EQUAL should only check the hash: - CScript p2sh2; - p2sh2.SetDestination(p2sh.GetID()); + CScript p2sh2 = GetScriptForDestination(CScriptID(p2sh)); CScript scriptSig2; scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh); - BOOST_CHECK(Verify(scriptSig2, p2sh2, true)); + BOOST_CHECK(Verify(scriptSig2, p2sh2, true, err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(set) { + LOCK(cs_main); // Test the CScript::Set* methods CBasicKeyStore keystore; CKey key[4]; - std::vector keys; + std::vector keys; for (int i = 0; i < 4; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); - keys.push_back(key[i]); + keys.push_back(key[i].GetPubKey()); } CScript inner[4]; - inner[0].SetDestination(key[0].GetPubKey().GetID()); - inner[1].SetMultisig(2, std::vector(keys.begin(), keys.begin()+2)); - inner[2].SetMultisig(1, std::vector(keys.begin(), keys.begin()+2)); - inner[3].SetMultisig(2, std::vector(keys.begin(), keys.begin()+3)); + inner[0] = GetScriptForDestination(key[0].GetPubKey().GetID()); + inner[1] = GetScriptForMultisig(2, std::vector(keys.begin(), keys.begin() + 2)); + inner[2] = GetScriptForMultisig(1, std::vector(keys.begin(), keys.begin() + 2)); + inner[3] = GetScriptForMultisig(2, std::vector(keys.begin(), keys.begin() + 3)); CScript outer[4]; for (int i = 0; i < 4; i++) { - outer[i].SetDestination(inner[i].GetID()); + outer[i] = GetScriptForDestination(CScriptID(inner[i])); keystore.AddCScript(inner[i]); } - CTransaction txFrom; // Funding transaction: + CMutableTransaction txFrom; // Funding transaction: + string reason; txFrom.vout.resize(4); for (int i = 0; i < 4; i++) { txFrom.vout[i].scriptPubKey = outer[i]; + txFrom.vout[i].nValue = CENT; } - BOOST_CHECK(txFrom.IsStandard()); + BOOST_CHECK(IsStandardTx(txFrom, reason)); - CTransaction txTo[4]; // Spending transactions + CMutableTransaction txTo[4]; // Spending transactions for (int i = 0; i < 4; i++) { txTo[i].vin.resize(1); txTo[i].vout.resize(1); txTo[i].vin[0].prevout.n = i; txTo[i].vin[0].prevout.hash = txFrom.GetHash(); - txTo[i].vout[0].nValue = 1; + txTo[i].vout[0].nValue = 1 * CENT; txTo[i].vout[0].scriptPubKey = inner[i]; - BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); +#ifdef ENABLE_WALLET + BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey, 0), strprintf("IsMine %d", i)); +#endif } for (int i = 0; i < 4; i++) { BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i)); - BOOST_CHECK_MESSAGE(txTo[i].IsStandard(), strprintf("txTo[%d].IsStandard", i)); + BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i)); } } @@ -196,29 +219,36 @@ BOOST_AUTO_TEST_CASE(is) // Test CScript::IsPayToScriptHash() uint160 dummy; CScript p2sh; - p2sh << OP_HASH160 << dummy << OP_EQUAL; + p2sh << OP_HASH160 << ToByteVector(dummy) << OP_EQUAL; BOOST_CHECK(p2sh.IsPayToScriptHash()); // Not considered pay-to-script-hash if using one of the OP_PUSHDATA opcodes: - static const unsigned char direct[] = { OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; - BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToScriptHash()); - static const unsigned char pushdata1[] = { OP_HASH160, OP_PUSHDATA1, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; - BOOST_CHECK(!CScript(pushdata1, pushdata1+sizeof(pushdata1)).IsPayToScriptHash()); - static const unsigned char pushdata2[] = { OP_HASH160, OP_PUSHDATA2, 20,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; - BOOST_CHECK(!CScript(pushdata2, pushdata2+sizeof(pushdata2)).IsPayToScriptHash()); - static const unsigned char pushdata4[] = { OP_HASH160, OP_PUSHDATA4, 20,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; - BOOST_CHECK(!CScript(pushdata4, pushdata4+sizeof(pushdata4)).IsPayToScriptHash()); + static const unsigned char direct[] = { + OP_HASH160, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUAL}; + BOOST_CHECK(CScript(direct, direct + sizeof(direct)).IsPayToScriptHash()); + static const unsigned char pushdata1[] = { + OP_HASH160, OP_PUSHDATA1, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUAL}; + BOOST_CHECK(!CScript(pushdata1, pushdata1 + sizeof(pushdata1)).IsPayToScriptHash()); + static const unsigned char pushdata2[] = { + OP_HASH160, OP_PUSHDATA2, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUAL}; + BOOST_CHECK(!CScript(pushdata2, pushdata2 + sizeof(pushdata2)).IsPayToScriptHash()); + static const unsigned char pushdata4[] = { + OP_HASH160, OP_PUSHDATA4, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUAL}; + BOOST_CHECK(!CScript(pushdata4, pushdata4 + sizeof(pushdata4)).IsPayToScriptHash()); CScript not_p2sh; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); - not_p2sh.clear(); not_p2sh << OP_HASH160 << dummy << dummy << OP_EQUAL; + not_p2sh.clear(); + not_p2sh << OP_HASH160 << ToByteVector(dummy) << ToByteVector(dummy) << OP_EQUAL; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); - not_p2sh.clear(); not_p2sh << OP_NOP << dummy << OP_EQUAL; + not_p2sh.clear(); + not_p2sh << OP_NOP << ToByteVector(dummy) << OP_EQUAL; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); - not_p2sh.clear(); not_p2sh << OP_HASH160 << dummy << OP_CHECKSIG; + not_p2sh.clear(); + not_p2sh << OP_HASH160 << ToByteVector(dummy) << OP_CHECKSIG; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); } @@ -226,104 +256,136 @@ BOOST_AUTO_TEST_CASE(switchover) { // Test switch over code CScript notValid; + ScriptError err; notValid << OP_11 << OP_12 << OP_EQUALVERIFY; CScript scriptSig; scriptSig << Serialize(notValid); - CScript fund; - fund.SetDestination(notValid.GetID()); + CScript fund = GetScriptForDestination(CScriptID(notValid)); // Validation should succeed under old rules (hash is correct): - BOOST_CHECK(Verify(scriptSig, fund, false)); + BOOST_CHECK(Verify(scriptSig, fund, false, err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); // Fail under new: - BOOST_CHECK(!Verify(scriptSig, fund, true)); + BOOST_CHECK(!Verify(scriptSig, fund, true, err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EQUALVERIFY, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(AreInputsStandard) { - std::map > mapInputs; + LOCK(cs_main); + CCoinsView coinsDummy; + CCoinsViewCache coins(&coinsDummy); CBasicKeyStore keystore; - CKey key[3]; - vector keys; - for (int i = 0; i < 3; i++) + CKey key[6]; + vector keys; + for (int i = 0; i < 6; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); - keys.push_back(key[i]); } + for (int i = 0; i < 3; i++) + keys.push_back(key[i].GetPubKey()); - CTransaction txFrom; - txFrom.vout.resize(6); + CMutableTransaction txFrom; + txFrom.vout.resize(7); // First three are standard: - CScript pay1; pay1.SetDestination(key[0].GetPubKey().GetID()); + CScript pay1 = GetScriptForDestination(key[0].GetPubKey().GetID()); keystore.AddCScript(pay1); - CScript payScriptHash1; payScriptHash1.SetDestination(pay1.GetID()); - CScript pay1of3; pay1of3.SetMultisig(1, keys); - - txFrom.vout[0].scriptPubKey = payScriptHash1; - txFrom.vout[1].scriptPubKey = pay1; - txFrom.vout[2].scriptPubKey = pay1of3; - - // Last three non-standard: - CScript empty; - keystore.AddCScript(empty); - txFrom.vout[3].scriptPubKey = empty; - // Can't use SetPayToScriptHash, it checks for the empty Script. So: - txFrom.vout[4].scriptPubKey << OP_HASH160 << Hash160(empty) << OP_EQUAL; - CScript oneOfEleven; - oneOfEleven << OP_1; - for (int i = 0; i < 11; i++) - oneOfEleven << key[0].GetPubKey(); - oneOfEleven << OP_11 << OP_CHECKMULTISIG; - txFrom.vout[5].scriptPubKey.SetDestination(oneOfEleven.GetID()); - - mapInputs[txFrom.GetHash()] = make_pair(CTxIndex(), txFrom); - - CTransaction txTo; + CScript pay1of3 = GetScriptForMultisig(1, keys); + + txFrom.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(pay1)); // P2SH (OP_CHECKSIG) + txFrom.vout[0].nValue = 1000; + txFrom.vout[1].scriptPubKey = pay1; // ordinary OP_CHECKSIG + txFrom.vout[1].nValue = 2000; + txFrom.vout[2].scriptPubKey = pay1of3; // ordinary OP_CHECKMULTISIG + txFrom.vout[2].nValue = 3000; + + // vout[3] is complicated 1-of-3 AND 2-of-3 + // ... that is OK if wrapped in P2SH: + CScript oneAndTwo; + oneAndTwo << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) + << ToByteVector(key[2].GetPubKey()); + oneAndTwo << OP_3 << OP_CHECKMULTISIGVERIFY; + oneAndTwo << OP_2 << ToByteVector(key[3].GetPubKey()) << ToByteVector(key[4].GetPubKey()) + << ToByteVector(key[5].GetPubKey()); + oneAndTwo << OP_3 << OP_CHECKMULTISIG; + keystore.AddCScript(oneAndTwo); + txFrom.vout[3].scriptPubKey = GetScriptForDestination(CScriptID(oneAndTwo)); + txFrom.vout[3].nValue = 4000; + + // vout[4] is max sigops: + CScript fifteenSigops; + fifteenSigops << OP_1; + for (unsigned i = 0; i < MAX_P2SH_SIGOPS; i++) + fifteenSigops << ToByteVector(key[i % 3].GetPubKey()); + fifteenSigops << OP_15 << OP_CHECKMULTISIG; + keystore.AddCScript(fifteenSigops); + txFrom.vout[4].scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops)); + txFrom.vout[4].nValue = 5000; + + // vout[5/6] are non-standard because they exceed MAX_P2SH_SIGOPS + CScript sixteenSigops; + sixteenSigops << OP_16 << OP_CHECKMULTISIG; + keystore.AddCScript(sixteenSigops); + txFrom.vout[5].scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops)); + txFrom.vout[5].nValue = 5000; + CScript twentySigops; + twentySigops << OP_CHECKMULTISIG; + keystore.AddCScript(twentySigops); + txFrom.vout[6].scriptPubKey = GetScriptForDestination(CScriptID(twentySigops)); + txFrom.vout[6].nValue = 6000; + + AddCoins(coins, txFrom, 0); + + CMutableTransaction txTo; txTo.vout.resize(1); - txTo.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID()); + txTo.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); - txTo.vin.resize(3); - txTo.vin[0].prevout.n = 0; - txTo.vin[0].prevout.hash = txFrom.GetHash(); + txTo.vin.resize(5); + for (int i = 0; i < 5; i++) + { + txTo.vin[i].prevout.n = i; + txTo.vin[i].prevout.hash = txFrom.GetHash(); + } BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0)); - txTo.vin[1].prevout.n = 1; - txTo.vin[1].prevout.hash = txFrom.GetHash(); BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1)); - txTo.vin[2].prevout.n = 2; - txTo.vin[2].prevout.hash = txFrom.GetHash(); BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2)); - - BOOST_CHECK(txTo.AreInputsStandard(mapInputs)); - BOOST_CHECK_EQUAL(txTo.GetP2SHSigOpCount(mapInputs), 1); - - // Make sure adding crap to the scriptSigs makes them non-standard: - for (int i = 0; i < 3; i++) - { - CScript t = txTo.vin[i].scriptSig; - txTo.vin[i].scriptSig = (CScript() << 11) + t; - BOOST_CHECK(!txTo.AreInputsStandard(mapInputs)); - txTo.vin[i].scriptSig = t; - } - - CTransaction txToNonStd; - txToNonStd.vout.resize(1); - txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID()); - txToNonStd.vin.resize(2); - txToNonStd.vin[0].prevout.n = 4; - txToNonStd.vin[0].prevout.hash = txFrom.GetHash(); - txToNonStd.vin[0].scriptSig << Serialize(empty); - txToNonStd.vin[1].prevout.n = 5; - txToNonStd.vin[1].prevout.hash = txFrom.GetHash(); - txToNonStd.vin[1].scriptSig << OP_0 << Serialize(oneOfEleven); - - BOOST_CHECK(!txToNonStd.AreInputsStandard(mapInputs)); - BOOST_CHECK_EQUAL(txToNonStd.GetP2SHSigOpCount(mapInputs), 11); - - txToNonStd.vin[0].scriptSig.clear(); - BOOST_CHECK(!txToNonStd.AreInputsStandard(mapInputs)); + // SignSignature doesn't know how to sign these. We're + // not testing validating signatures, so just create + // dummy signatures that DO include the correct P2SH scripts: + txTo.vin[3].scriptSig << OP_11 << OP_11 << vector(oneAndTwo.begin(), oneAndTwo.end()); + txTo.vin[4].scriptSig << vector(fifteenSigops.begin(), fifteenSigops.end()); + + BOOST_CHECK(::AreInputsStandard(txTo, coins)); + // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4] + BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U); + + CMutableTransaction txToNonStd1; + txToNonStd1.vout.resize(1); + txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); + txToNonStd1.vout[0].nValue = 1000; + txToNonStd1.vin.resize(1); + txToNonStd1.vin[0].prevout.n = 5; + txToNonStd1.vin[0].prevout.hash = txFrom.GetHash(); + txToNonStd1.vin[0].scriptSig << vector(sixteenSigops.begin(), sixteenSigops.end()); + + BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins)); + BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U); + + CMutableTransaction txToNonStd2; + txToNonStd2.vout.resize(1); + txToNonStd2.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); + txToNonStd2.vout[0].nValue = 1000; + txToNonStd2.vin.resize(1); + txToNonStd2.vin[0].prevout.n = 6; + txToNonStd2.vin[0].prevout.hash = txFrom.GetHash(); + txToNonStd2.vin[0].scriptSig << vector(twentySigops.begin(), twentySigops.end()); + + BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins)); + BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 760c3140..3cc98537 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1,172 +1,964 @@ -#include +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "data/script_tests.json.h" + +#include "core_io.h" +#include "key.h" +#include "keystore.h" +#include "rpc/server.h" +#include "script/script.h" +#include "script/script_error.h" +#include "script/sign.h" +#include "test/test_bitcoin.h" +#include "util.h" +#include "utilstrencodings.h" + +#if defined(HAVE_CONSENSUS_LIB) +#include "script/bitcoinconsensus.h" +#endif + #include +#include +#include #include -#include -#include -#include -#include -#include + +#include #include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_writer_template.h" -#include "json/json_spirit_utils.h" -#include "main.h" -#include "wallet.h" +#include using namespace std; -using namespace json_spirit; -using namespace boost::algorithm; -extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); -extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, int nHashType); +// Uncomment if you want to output updated JSON tests. +// #define UPDATE_JSON_TESTS -CScript -ParseScript(string s) +#ifdef BITCOIN_CASH +static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID; +#else +static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; +#endif + +unsigned int ParseScriptFlags(string strFlags); +string FormatScriptFlags(unsigned int flags); + +UniValue read_json(const std::string &jsondata) { - CScript result; + UniValue v; - static map mapOpNames; + if (!v.read(jsondata) || !v.isArray()) + { + BOOST_ERROR("Parse error."); + return UniValue(UniValue::VARR); + } + 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_SIG_NULLFAIL, "NULLFAIL"}, + {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) - if (mapOpNames.size() == 0) +CMutableTransaction BuildCreditingTransaction(const CScript &scriptPubKey, CAmount nValue) +{ + CMutableTransaction txCredit; + txCredit.nVersion = 1; + txCredit.nLockTime = 0; + txCredit.vin.resize(1); + txCredit.vout.resize(1); + txCredit.vin[0].prevout.SetNull(); + txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0); + txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; + txCredit.vout[0].scriptPubKey = scriptPubKey; + txCredit.vout[0].nValue = nValue; + + return txCredit; +} + +CMutableTransaction BuildSpendingTransaction(const CScript &scriptSig, const CMutableTransaction &txCredit) +{ + CMutableTransaction txSpend; + txSpend.nVersion = 1; + txSpend.nLockTime = 0; + txSpend.vin.resize(1); + txSpend.vout.resize(1); + txSpend.vin[0].prevout.hash = txCredit.GetHash(); + txSpend.vin[0].prevout.n = 0; + txSpend.vin[0].scriptSig = scriptSig; + txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; + txSpend.vout[0].scriptPubKey = CScript(); + txSpend.vout[0].nValue = txCredit.vout[0].nValue; + + return txSpend; +} + +void DoTest(const CScript &scriptPubKey, + const CScript &scriptSig, + int flags, + const std::string &message, + int scriptError, + CAmount nValue) +{ + bool expect = (scriptError == SCRIPT_ERR_OK); + ScriptError err; + CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey, nValue); + CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit); + CMutableTransaction tx2 = tx; + bool result = VerifyScript(scriptSig, scriptPubKey, flags, + MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue, flags), &err); + BOOST_CHECK_MESSAGE(result == expect, message); + BOOST_CHECK_MESSAGE(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; + if (nValue == 0) { - for (int op = OP_NOP; op <= OP_NOP10; op++) - { - const char* name = GetOpName((opcodetype)op); - if (strcmp(name, "OP_UNKNOWN") == 0) - continue; - string strName(name); - mapOpNames[strName] = (opcodetype)op; - // Convenience: OP_ADD and just ADD are both recognized: - replace_first(strName, "OP_", ""); - mapOpNames[strName] = (opcodetype)op; - } + BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(begin_ptr(scriptPubKey), scriptPubKey.size(), + (const unsigned char *)&stream[0], stream.size(), 0, flags, NULL) == expect, + message); } +#endif +} - vector words; - split(words, s, is_any_of(" \t\n"), token_compress_on); +void static NegateSignatureS(std::vector &vchSig) +{ + // Parse the signature. + std::vector r, s; + r = std::vector(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]); + s = std::vector( + vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]); - for (auto w: words) + // Really ugly to implement mod-n negation here, but it would be feature creep to expose such functionality from + // libsecp256k1. + static const unsigned char order[33] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, + 0x36, 0x41, 0x41}; + while (s.size() < 33) { - if (all(w, is_digit()) || - (starts_with(w, "-") && all(string(w.begin()+1, w.end()), is_digit()))) - { - // Number - int64 n = atoi64(w); - result << n; - } - else if (starts_with(w, "0x") && IsHex(string(w.begin()+2, w.end()))) - { - // Raw hex data, inserted NOT pushed onto stack: - std::vector raw = ParseHex(string(w.begin()+2, w.end())); - result.insert(result.end(), raw.begin(), raw.end()); - } - else if (w.size() >= 2 && starts_with(w, "'") && ends_with(w, "'")) + s.insert(s.begin(), 0x00); + } + int carry = 0; + for (int p = 32; p >= 1; p--) + { + int n = (int)order[p] - s[p] - carry; + s[p] = (n + 256) & 0xFF; + carry = (n < 0); + } + assert(carry == 0); + if (s.size() > 1 && s[0] == 0 && s[1] < 0x80) + { + s.erase(s.begin()); + } + + // Reconstruct the signature. + vchSig.clear(); + vchSig.push_back(0x30); + vchSig.push_back(4 + r.size() + s.size()); + vchSig.push_back(0x02); + vchSig.push_back(r.size()); + vchSig.insert(vchSig.end(), r.begin(), r.end()); + vchSig.push_back(0x02); + vchSig.push_back(s.size()); + vchSig.insert(vchSig.end(), s.begin(), s.end()); +} + +namespace +{ +const unsigned char vchKey0[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; +const unsigned char vchKey1[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}; +const unsigned char vchKey2[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; + +struct KeyData +{ + CKey key0, key0C, key1, key1C, key2, key2C; + CPubKey pubkey0, pubkey0C, pubkey0H; + CPubKey pubkey1, pubkey1C; + CPubKey pubkey2, pubkey2C; + + KeyData() + { + key0.Set(vchKey0, vchKey0 + 32, false); + key0C.Set(vchKey0, vchKey0 + 32, true); + pubkey0 = key0.GetPubKey(); + pubkey0H = key0.GetPubKey(); + pubkey0C = key0C.GetPubKey(); + *const_cast(&pubkey0H[0]) = 0x06 | (pubkey0H[64] & 1); + + key1.Set(vchKey1, vchKey1 + 32, false); + key1C.Set(vchKey1, vchKey1 + 32, true); + pubkey1 = key1.GetPubKey(); + pubkey1C = key1C.GetPubKey(); + + key2.Set(vchKey2, vchKey2 + 32, false); + key2C.Set(vchKey2, vchKey2 + 32, true); + pubkey2 = key2.GetPubKey(); + pubkey2C = key2C.GetPubKey(); + } +}; + + +class TestBuilder +{ +private: + //! Actually executed script + CScript script; + //! The P2SH redeemscript + CScript redeemscript; + CTransactionRef creditTx; + CMutableTransaction spendTx; + bool havePush; + std::vector push; + std::string comment; + int flags; + int scriptError; + CAmount nValue; + + void DoPush() + { + if (havePush) { - // Single-quoted string, pushed as data. NOTE: this is poor-man's - // parsing, spaces/tabs/newlines in single-quoted strings won't work. - std::vector value(w.begin()+1, w.end()-1); - result << value; + spendTx.vin[0].scriptSig << push; + havePush = false; } - else if (mapOpNames.count(w)) + } + + void DoPush(const std::vector &data) + { + DoPush(); + push = data; + havePush = true; + } + +public: + TestBuilder(const CScript &script_, const std::string &comment_, int flags_, bool P2SH = false, CAmount nValue_ = 0) + : script(script_), havePush(false), comment(comment_), flags(flags_), scriptError(SCRIPT_ERR_OK), + nValue(nValue_) + { + CScript scriptPubKey = script; + if (P2SH) { - // opcode, e.g. OP_ADD or OP_1: - result << mapOpNames[w]; + redeemscript = scriptPubKey; + scriptPubKey = CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemscript)) << OP_EQUAL; } - else + creditTx = MakeTransactionRef(BuildCreditingTransaction(scriptPubKey, nValue)); + spendTx = BuildSpendingTransaction(CScript(), *creditTx); + } + + TestBuilder &ScriptError(ScriptError_t err) + { + scriptError = err; + return *this; + } + + TestBuilder &Add(const CScript &script) + { + DoPush(); + spendTx.vin[0].scriptSig += script; + return *this; + } + + TestBuilder &Num(int num) + { + DoPush(); + spendTx.vin[0].scriptSig << num; + return *this; + } + + TestBuilder &Push(const std::string &hex) + { + DoPush(ParseHex(hex)); + return *this; + } + + TestBuilder &PushSig(const CKey &key, + int nHashType = SIGHASH_ALL, + unsigned int lenR = 32, + unsigned int lenS = 32, + CAmount amount = 0) + { + uint256 hash = SignatureHash(script, spendTx, 0, nHashType, amount); + std::vector vchSig, r, s; + uint32_t iter = 0; + do { - BOOST_ERROR("Parse error: " << s); - return CScript(); - } + key.Sign(hash, vchSig, iter++); + if ((lenS == 33) != (vchSig[5 + vchSig[3]] == 33)) + { + NegateSignatureS(vchSig); + } + r = std::vector(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]); + s = std::vector( + vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]); + } while (lenR != r.size() || lenS != s.size()); + vchSig.push_back(static_cast(nHashType)); + DoPush(vchSig); + return *this; } - return result; -} + TestBuilder &Push(const CPubKey &pubkey) + { + DoPush(std::vector(pubkey.begin(), pubkey.end())); + return *this; + } -Array -read_json(const std::string& filename) -{ - namespace fs = boost::filesystem; - fs::path testFile = fs::current_path() / "test" / "data" / filename; + TestBuilder &PushRedeem() + { + DoPush(std::vector(redeemscript.begin(), redeemscript.end())); + return *this; + } -#ifdef TEST_DATA_DIR - if (!fs::exists(testFile)) + TestBuilder &EditPush(unsigned int pos, const std::string &hexin, const std::string &hexout) { - testFile = fs::path(BOOST_PP_STRINGIZE(TEST_DATA_DIR)) / filename; + assert(havePush); + std::vector datain = ParseHex(hexin); + std::vector dataout = ParseHex(hexout); + assert(pos + datain.size() <= push.size()); + BOOST_CHECK_MESSAGE( + std::vector(push.begin() + pos, push.begin() + pos + datain.size()) == datain, comment); + push.erase(push.begin() + pos, push.begin() + pos + datain.size()); + push.insert(push.begin() + pos, dataout.begin(), dataout.end()); + return *this; } -#endif - ifstream ifs(testFile.string().c_str(), ifstream::in); - Value v; - if (!read_stream(ifs, v)) + TestBuilder &DamagePush(unsigned int pos) { - if (ifs.fail()) - BOOST_ERROR("Cound not find/open " << filename); - else - BOOST_ERROR("JSON syntax error in " << filename); - return Array(); + assert(havePush); + assert(pos < push.size()); + push[pos] ^= 1; + return *this; } - if (v.type() != array_type) + + TestBuilder &Test() { - BOOST_ERROR(filename << " does not contain a json array"); - return Array(); + TestBuilder copy = *this; // Make a copy so we can rollback the push. + DoPush(); + DoTest(creditTx->vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, comment, scriptError, nValue); + *this = copy; + return *this; } - return v.get_array(); -} + UniValue GetJSON() + { + DoPush(); + UniValue array(UniValue::VARR); + if (nValue != 0) + { + UniValue amount(UniValue::VARR); + amount.push_back(ValueFromAmount(nValue)); + array.push_back(amount); + } + array.push_back(FormatScript(spendTx.vin[0].scriptSig)); + array.push_back(FormatScript(creditTx->vout[0].scriptPubKey)); + array.push_back(FormatScriptFlags(flags)); + array.push_back(FormatScriptError((ScriptError_t)scriptError)); + array.push_back(comment); + return array; + } -BOOST_AUTO_TEST_SUITE(script_tests) + std::string GetComment() { return comment; } + const CScript &GetScriptPubKey() { return creditTx->vout[0].scriptPubKey; } +}; -BOOST_AUTO_TEST_CASE(script_valid) +std::string JSONPrettyPrint(const UniValue &univalue) { - // Read tests from test/data/script_valid.json - // Format is an array of arrays - // Inner arrays are [ "scriptSig", "scriptPubKey" ] - // ... where scriptSig and scriptPubKey are stringified - // scripts. - Array tests = read_json("script_valid.json"); + std::string ret = univalue.write(4); + // Workaround for libunivalue pretty printer, which puts a space between comma's and newlines + size_t pos = 0; + while ((pos = ret.find(" \n", pos)) != std::string::npos) + { + ret.replace(pos, 2, "\n"); + pos++; + } + return ret; +} +} + +BOOST_AUTO_TEST_CASE(script_build) +{ + const KeyData keys; + + std::vector tests; + + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK", 0).PushSig(keys.key0)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK, bad sig", 0) + .PushSig(keys.key0) + .DamagePush(10) + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + + tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1C.GetID()) + << OP_EQUALVERIFY << OP_CHECKSIG, + "P2PKH", 0) + .PushSig(keys.key1) + .Push(keys.pubkey1C)); + tests.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) + .ScriptError(SCRIPT_ERR_EQUALVERIFY)); + + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK anyonecanpay", 0) + .PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY)); + tests.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") + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, "P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true) + .PushSig(keys.key0) + .PushRedeem()); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, "P2SH(P2PK), bad redeemscript", + SCRIPT_VERIFY_P2SH, true) + .PushSig(keys.key0) + .PushRedeem() + .DamagePush(10) + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + + tests.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()); + tests.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() + .ScriptError(SCRIPT_ERR_EQUALVERIFY)); + + tests.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)); + tests.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) + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + + tests.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()); + tests.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() + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + + tests.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")); + tests.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") + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.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")); + tests.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") + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.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")); + tests.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") + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.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)); + tests.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) + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.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") + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.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") + .ScriptError(SCRIPT_ERR_SIG_DER)); + + tests.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")); + tests.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") + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.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") + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.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") + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 3, without DERSIG", 0) + .Num(0) + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 3, with DERSIG", + SCRIPT_VERIFY_DERSIG) + .Num(0) + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, + "BIP66 example 4, without DERSIG", 0) + .Num(0)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, + "BIP66 example 4, with DERSIG", SCRIPT_VERIFY_DERSIG) + .Num(0)); + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 5, without DERSIG", 0) + .Num(1) + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 5, with DERSIG", + SCRIPT_VERIFY_DERSIG) + .Num(1) + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, + "BIP66 example 6, without DERSIG", 0) + .Num(1)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, + "BIP66 example 6, with DERSIG", SCRIPT_VERIFY_DERSIG) + .Num(1) + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.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)); + tests.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) + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.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) + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.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) + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.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") + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.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") + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.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")); + tests.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") + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.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) + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.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) + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.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)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 + << OP_CHECKMULTISIG << OP_NOT, + "BIP66 example 12, with DERSIG", SCRIPT_VERIFY_DERSIG) + .Num(0) + .PushSig(keys.key1, SIGHASH_ALL, 33, 32) + .EditPush(1, "45022100", "440220") + .Num(0)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, + "P2PK with multi-byte hashtype, without DERSIG", 0) + .PushSig(keys.key2, SIGHASH_ALL) + .EditPush(70, "01", "0101")); + tests.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") + .ScriptError(SCRIPT_ERR_SIG_DER)); + + tests.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)); + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with high S", SCRIPT_VERIFY_LOW_S) + .PushSig(keys.key2, SIGHASH_ALL, 32, 33) + .ScriptError(SCRIPT_ERR_SIG_HIGH_S)); + + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, + "P2PK with hybrid pubkey but no STRICTENC", 0) + .PushSig(keys.key0, SIGHASH_ALL)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, "P2PK with hybrid pubkey", + SCRIPT_VERIFY_STRICTENC) + .PushSig(keys.key0, SIGHASH_ALL) + .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); + tests.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) + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, + "P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC) + .PushSig(keys.key0, SIGHASH_ALL) + .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); + tests.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)); + tests.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) + .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); + tests.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)); + tests.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", SCRIPT_VERIFY_STRICTENC) + .Num(0) + .PushSig(keys.key1, SIGHASH_ALL)); + tests.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) + .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); + + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, + "P2PK with undefined hashtype but no STRICTENC", 0) + .PushSig(keys.key1, 5)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK with undefined hashtype", + SCRIPT_VERIFY_STRICTENC) + .PushSig(keys.key1, 5) + .ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); + tests.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)); + tests.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) + .ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); + + tests.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)); + tests.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) + .ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); + tests.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)); + tests.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) + .ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); + + tests.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)); + tests.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) + .ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, + "P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY", 0, true) + .PushSig(keys.key2) + .Add(CScript() << OP_NOP8) + .PushRedeem()); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, + "P2PK with non-push scriptSig but with P2SH validation", 0) + .PushSig(keys.key2) + .Add(CScript() << OP_NOP8)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, + "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", SCRIPT_VERIFY_P2SH, true) + .PushSig(keys.key2) + .Add(CScript() << OP_NOP8) + .PushRedeem() + .ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, + "P2SH(P2PK) with non-push scriptSig but not P2SH", SCRIPT_VERIFY_SIGPUSHONLY, true) + .PushSig(keys.key2) + .Add(CScript() << OP_NOP8) + .PushRedeem() + .ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); + tests.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH) + .Num(11) + .PushSig(keys.key0)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK with unnecessary input", + SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH) + .Num(11) + .PushSig(keys.key0) + .ScriptError(SCRIPT_ERR_CLEANSTACK)); + tests.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()); + tests.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() + .ScriptError(SCRIPT_ERR_CLEANSTACK)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with CLEANSTACK", + SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true) + .PushSig(keys.key0) + .PushRedeem()); + + static const CAmount TEST_AMOUNT = 12345000000000; + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK FORKID", + SCRIPT_ENABLE_SIGHASH_FORKID, false, TEST_AMOUNT) + .PushSig(keys.key0, SIGHASH_ALL | SIGHASH_FORKID, 32, 32, TEST_AMOUNT)); + + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK INVALID AMOUNT", + SCRIPT_ENABLE_SIGHASH_FORKID, false, TEST_AMOUNT) + .PushSig(keys.key0, SIGHASH_ALL | SIGHASH_FORKID, 32, 32, TEST_AMOUNT + 1) + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK INVALID FORKID", 0, false, + TEST_AMOUNT) + .PushSig(keys.key0, SIGHASH_ALL | SIGHASH_FORKID, 32, 32, TEST_AMOUNT) + .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + + std::set tests_set; - for (auto& tv: tests) { - Array test = tv.get_array(); - string strTest = write_string(tv, false); - if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments) + UniValue json_tests = read_json( + std::string(json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); + + for (unsigned int idx = 0; idx < json_tests.size(); idx++) { - BOOST_ERROR("Bad test: " << strTest); - continue; + const UniValue &tv = json_tests[idx]; + tests_set.insert(JSONPrettyPrint(tv.get_array())); } - string scriptSigString = test[0].get_str(); - CScript scriptSig = ParseScript(scriptSigString); - string scriptPubKeyString = test[1].get_str(); - CScript scriptPubKey = ParseScript(scriptPubKeyString); + } + + std::string strGen; - CTransaction tx; - BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest); + BOOST_FOREACH (TestBuilder &test, tests) + { + test.Test(); + std::string str = JSONPrettyPrint(test.GetJSON()); +#ifndef UPDATE_JSON_TESTS + if (tests_set.count(str) == 0) + { + BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment()); + } +#endif + strGen += str + ",\n"; } + +#ifdef UPDATE_JSON_TESTS + FILE *file = fopen("script_tests.json.gen", "w"); + fputs(strGen.c_str(), file); + fclose(file); +#endif } -BOOST_AUTO_TEST_CASE(script_invalid) +BOOST_AUTO_TEST_CASE(script_json_test) { - // Scripts that should evaluate as invalid - Array tests = read_json("script_invalid.json"); + // Read tests from test/data/script_tests.json + // Format is an array of arrays + // Inner arrays are [ ["wit"..., nValue]?, "scriptSig", "scriptPubKey", "flags", "expected_scripterror" ] + // ... where scriptSig and scriptPubKey are stringified + // scripts. + UniValue tests = + read_json(std::string(json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); - for (auto& tv: tests) + for (unsigned int idx = 0; idx < tests.size(); idx++) { - Array test = tv.get_array(); - string strTest = write_string(tv, false); - if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments) + UniValue test = tests[idx]; + string strTest = test.write(); + CAmount nValue = 0; + unsigned int pos = 0; + if (test.size() > 0 && test[pos].isArray()) { - BOOST_ERROR("Bad test: " << strTest); + nValue = AmountFromValue(test[pos][0]); + pos++; + } + + // Allow size > 3; extra stuff ignored (useful for comments) + if (test.size() < 4 + pos) + { + if (test.size() != 1) + BOOST_ERROR("Bad test: " << strTest); continue; } - string scriptSigString = test[0].get_str(); + string scriptSigString = test[pos++].get_str(); CScript scriptSig = ParseScript(scriptSigString); - string scriptPubKeyString = test[1].get_str(); + string scriptPubKeyString = test[pos++].get_str(); CScript scriptPubKey = ParseScript(scriptPubKeyString); + unsigned int scriptflags = ParseScriptFlags(test[pos++].get_str()); + int scriptError = ParseScriptError(test[pos++].get_str()); - CTransaction tx; - BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest); + DoTest(scriptPubKey, scriptSig, scriptflags, strTest, scriptError, nValue); } } @@ -174,94 +966,110 @@ BOOST_AUTO_TEST_CASE(script_PushData) { // Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on // the stack as the 1-75 opcodes do. - static const unsigned char direct[] = { 1, 0x5a }; - static const unsigned char pushdata1[] = { OP_PUSHDATA1, 1, 0x5a }; - static const unsigned char pushdata2[] = { OP_PUSHDATA2, 1, 0, 0x5a }; - static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a }; + static const unsigned char direct[] = {1, 0x5a}; + static const unsigned char pushdata1[] = {OP_PUSHDATA1, 1, 0x5a}; + static const unsigned char pushdata2[] = {OP_PUSHDATA2, 1, 0, 0x5a}; + static const unsigned char pushdata4[] = {OP_PUSHDATA4, 1, 0, 0, 0, 0x5a}; + ScriptError err; vector > directStack; - BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, 0)); + BOOST_CHECK(EvalScript( + directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); vector > pushdata1Stack; - BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, 0)); + BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, + BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata1Stack == directStack); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); vector > pushdata2Stack; - BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, 0)); + BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, + BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata2Stack == directStack); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); vector > pushdata4Stack; - BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, 0)); + BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, + BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata4Stack == directStack); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } -CScript -sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction) +CScript sign_multisig(const CScript &scriptPubKey, std::vector keys, const CTransaction &transaction, CAmount amt) { - uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL); +#ifdef BITCOIN_CASH + unsigned char sighashType = SIGHASH_ALL | SIGHASH_FORKID; +#else + unsigned char sighashType = SIGHASH_ALL; +#endif + + uint256 hash = SignatureHash(scriptPubKey, transaction, 0, sighashType, amt, 0); CScript result; // // NOTE: CHECKMULTISIG has an unfortunate bug; it requires // one extra item on the stack, before the signatures. // Putting OP_0 on the stack is the workaround; - // fixing the bug would mean splitting the blockchain (old + // fixing the bug would mean splitting the block chain (old // clients would not accept new CHECKMULTISIG transactions, // and vice-versa) // result << OP_0; - for (auto key: keys) + BOOST_FOREACH (const CKey &key, keys) { vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); - vchSig.push_back((unsigned char)SIGHASH_ALL); + vchSig.push_back(sighashType); result << vchSig; } return result; } -CScript -sign_multisig(CScript scriptPubKey, CKey key, CTransaction transaction) +CScript sign_multisig(const CScript &scriptPubKey, const CKey &key, const CTransaction &transaction, CAmount amt) { std::vector keys; keys.push_back(key); - return sign_multisig(scriptPubKey, keys, transaction); + return sign_multisig(scriptPubKey, keys, transaction, amt); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) { + ScriptError err; CKey key1, key2, key3; key1.MakeNewKey(true); key2.MakeNewKey(false); key3.MakeNewKey(true); CScript scriptPubKey12; - scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG; - - CTransaction txFrom12; - txFrom12.vout.resize(1); - txFrom12.vout[0].scriptPubKey = scriptPubKey12; + scriptPubKey12 << OP_1 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << OP_2 + << OP_CHECKMULTISIG; - CTransaction txTo12; - txTo12.vin.resize(1); - txTo12.vout.resize(1); - txTo12.vin[0].prevout.n = 0; - txTo12.vin[0].prevout.hash = txFrom12.GetHash(); - txTo12.vout[0].nValue = 1; + CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12, 1); + CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); - CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, 0)); + CScript goodsig1 = sign_multisig(scriptPubKey12, key1, CTransaction(txTo12), txFrom12.vout[0].nValue); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, + MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); txTo12.vout[0].nValue = 2; - BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, 0)); + BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, + MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); - CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, true, 0)); + CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12, txFrom12.vout[0].nValue); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, + MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); - CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, true, 0)); + CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12, txFrom12.vout[0].nValue); + BOOST_CHECK(!VerifyScript( + badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) { + ScriptError err; CKey key1, key2, key3, key4; key1.MakeNewKey(true); key2.MakeNewKey(false); @@ -269,147 +1077,183 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) key4.MakeNewKey(false); CScript scriptPubKey23; - scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG; + scriptPubKey23 << OP_2 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) + << ToByteVector(key3.GetPubKey()) << OP_3 << OP_CHECKMULTISIG; - CTransaction txFrom23; - txFrom23.vout.resize(1); - txFrom23.vout[0].scriptPubKey = scriptPubKey23; - - CTransaction txTo23; - txTo23.vin.resize(1); - txTo23.vout.resize(1); - txTo23.vin[0].prevout.n = 0; - txTo23.vin[0].prevout.hash = txFrom23.GetHash(); - txTo23.vout[0].nValue = 1; + CMutableTransaction txFrom23 = BuildCreditingTransaction(scriptPubKey23, 0); + CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), txFrom23); std::vector keys; - keys.push_back(key1); keys.push_back(key2); - CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, true, 0)); + keys.push_back(key1); + keys.push_back(key2); + CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23, txFrom23.vout[0].nValue); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, + MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); - keys.push_back(key1); keys.push_back(key3); - CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, true, 0)); + keys.push_back(key1); + keys.push_back(key3); + CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23, txFrom23.vout[0].nValue); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, + MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); - keys.push_back(key2); keys.push_back(key3); - CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, true, 0)); + keys.push_back(key2); + keys.push_back(key3); + CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23, txFrom23.vout[0].nValue); + BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, + MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); - keys.push_back(key2); keys.push_back(key2); // Can't re-use sig - CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, true, 0)); + keys.push_back(key2); + keys.push_back(key2); // Can't re-use sig + CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23, txFrom23.vout[0].nValue); + BOOST_CHECK(!VerifyScript( + badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); - keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order - CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, true, 0)); + keys.push_back(key2); + keys.push_back(key1); // sigs must be in correct order + CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23, txFrom23.vout[0].nValue); + BOOST_CHECK(!VerifyScript( + badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); - keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order - CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, true, 0)); + keys.push_back(key3); + keys.push_back(key2); // sigs must be in correct order + CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23, txFrom23.vout[0].nValue); + BOOST_CHECK(!VerifyScript( + badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); - keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys - CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, true, 0)); + keys.push_back(key4); + keys.push_back(key2); // sigs must match pubkeys + CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23, txFrom23.vout[0].nValue); + BOOST_CHECK(!VerifyScript( + badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); - keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys - CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, true, 0)); + keys.push_back(key1); + keys.push_back(key4); // sigs must match pubkeys + CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23, txFrom23.vout[0].nValue); + BOOST_CHECK(!VerifyScript( + badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); // Must have signatures - CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, true, 0)); -} + CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23, txFrom23.vout[0].nValue); + BOOST_CHECK(!VerifyScript( + badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); +} BOOST_AUTO_TEST_CASE(script_combineSigs) { // Test the CombineSignatures function + CAmount amount = 0; CBasicKeyStore keystore; vector keys; + vector pubkeys; for (int i = 0; i < 3; i++) { CKey key; - key.MakeNewKey(i%2 == 1); + key.MakeNewKey(i % 2 == 1); keys.push_back(key); + pubkeys.push_back(key.GetPubKey()); keystore.AddKey(key); } - CTransaction txFrom; - txFrom.vout.resize(1); - txFrom.vout[0].scriptPubKey.SetDestination(keys[0].GetPubKey().GetID()); - CScript& scriptPubKey = txFrom.vout[0].scriptPubKey; - CTransaction txTo; - txTo.vin.resize(1); - txTo.vout.resize(1); - txTo.vin[0].prevout.n = 0; - txTo.vin[0].prevout.hash = txFrom.GetHash(); - CScript& scriptSig = txTo.vin[0].scriptSig; - txTo.vout[0].nValue = 1; + CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID()), 0); + CMutableTransaction txTo = BuildSpendingTransaction(CScript(), txFrom); + CScript &scriptPubKey = txFrom.vout[0].scriptPubKey; + CScript &scriptSig = txTo.vin[0].scriptSig; CScript empty; - CScript combined = CombineSignatures(scriptPubKey, txTo, 0, empty, empty); + CScript combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty); BOOST_CHECK(combined.empty()); // Single signature case: SignSignature(keystore, txFrom, txTo, 0); // changes scriptSig - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), scriptSig, empty); BOOST_CHECK(combined == scriptSig); - combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, scriptSig); BOOST_CHECK(combined == scriptSig); CScript scriptSigCopy = scriptSig; // Signing again will give a different, valid signature: SignSignature(keystore, txFrom, txTo, 0); - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); + combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), scriptSigCopy, scriptSig); BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig); // P2SH, single-signature case: - CScript pkSingle; pkSingle << keys[0].GetPubKey() << OP_CHECKSIG; + CScript pkSingle; + pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG; keystore.AddCScript(pkSingle); - scriptPubKey.SetDestination(pkSingle.GetID()); + scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); SignSignature(keystore, txFrom, txTo, 0); - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), scriptSig, empty); BOOST_CHECK(combined == scriptSig); - combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, scriptSig); BOOST_CHECK(combined == scriptSig); scriptSigCopy = scriptSig; SignSignature(keystore, txFrom, txTo, 0); - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); + combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), scriptSigCopy, scriptSig); BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig); // dummy scriptSigCopy with placeholder, should always choose non-placeholder: - scriptSigCopy = CScript() << OP_0 << static_cast >(pkSingle); - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); + scriptSigCopy = CScript() << OP_0 << vector(pkSingle.begin(), pkSingle.end()); + combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), scriptSigCopy, scriptSig); BOOST_CHECK(combined == scriptSig); - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, scriptSigCopy); + combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), scriptSig, scriptSigCopy); BOOST_CHECK(combined == scriptSig); // Hardest case: Multisig 2-of-3 - scriptPubKey.SetMultisig(2, keys); + scriptPubKey = GetScriptForMultisig(2, pubkeys); keystore.AddCScript(scriptPubKey); SignSignature(keystore, txFrom, txTo, 0); - combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), scriptSig, empty); BOOST_CHECK(combined == scriptSig); - combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, scriptSig); BOOST_CHECK(combined == scriptSig); - // A couple of partially-signed versions: +// A couple of partially-signed versions: +#ifdef BITCOIN_CASH vector sig1; - uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL); + uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL | SIGHASH_FORKID, 0); + BOOST_CHECK(keys[0].Sign(hash1, sig1)); + sig1.push_back(SIGHASH_ALL | SIGHASH_FORKID); + vector sig2; + uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE | SIGHASH_FORKID, 0); + BOOST_CHECK(keys[1].Sign(hash2, sig2)); + sig2.push_back(SIGHASH_NONE | SIGHASH_FORKID); + vector sig3; + uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE | SIGHASH_FORKID, 0); + BOOST_CHECK(keys[2].Sign(hash3, sig3)); + sig3.push_back(SIGHASH_SINGLE | SIGHASH_FORKID); +#else + vector sig1; + uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0); BOOST_CHECK(keys[0].Sign(hash1, sig1)); sig1.push_back(SIGHASH_ALL); vector sig2; - uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE); + uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0); BOOST_CHECK(keys[1].Sign(hash2, sig2)); sig2.push_back(SIGHASH_NONE); vector sig3; - uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE); + uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0); BOOST_CHECK(keys[2].Sign(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); +#endif // Not fussy about order (or even existence) of placeholders or signatures: CScript partial1a = CScript() << OP_0 << sig1 << OP_0; @@ -423,22 +1267,231 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) CScript complete13 = CScript() << OP_0 << sig1 << sig3; CScript complete23 = CScript() << OP_0 << sig2 << sig3; - combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial1b); + combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), partial1a, partial1b); BOOST_CHECK(combined == partial1a); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial2a); + combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), partial1a, partial2a); BOOST_CHECK(combined == complete12); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial2a, partial1a); + combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), partial2a, partial1a); BOOST_CHECK(combined == complete12); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial1b, partial2b); + combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), partial1b, partial2b); BOOST_CHECK(combined == complete12); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial1b); + combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), partial3b, partial1b); BOOST_CHECK(combined == complete13); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial2a, partial3a); + combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), partial2a, partial3a); BOOST_CHECK(combined == complete23); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial2b); + combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), partial3b, partial2b); BOOST_CHECK(combined == complete23); - combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial3a); + combined = + CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), partial3b, partial3a); BOOST_CHECK(combined == partial3c); } +BOOST_AUTO_TEST_CASE(script_standard_push) +{ + ScriptError err; + for (int i = 0; i < 67000; i++) + { + CScript script; + script << i; + BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push."); + BOOST_CHECK_MESSAGE( + VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), + "Number " << i << " push is not minimal data."); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); + } + + for (unsigned int i = 0; i <= MAX_SCRIPT_ELEMENT_SIZE; i++) + { + std::vector data(i, '\111'); + CScript script; + script << data; + BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push."); + BOOST_CHECK_MESSAGE( + VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), + "Length " << i << " push is not minimal data."); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); + } +} + +BOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts) +{ + // IsPushOnly returns false when given a script containing only pushes that + // are invalid due to truncation. IsPushOnly() is consensus critical + // because P2SH evaluation uses it, although this specific behavior should + // not be consensus critical as the P2SH evaluation would fail first due to + // the invalid push. Still, it doesn't hurt to test it explicitly. + static const unsigned char direct[] = {1}; + BOOST_CHECK(!CScript(direct, direct + sizeof(direct)).IsPushOnly()); +} + +BOOST_AUTO_TEST_CASE(script_GetScriptAsm) +{ + BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2, true)); + BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true)); + BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2)); + BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY)); + + string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a" + "870f3dcf38d782e53023ee313d741ad0cfbc0c5090"); + string pubKey("03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2"); + vector vchPubKey = ToByteVector(ParseHex(pubKey)); + + BOOST_CHECK_EQUAL( + derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey, true)); + BOOST_CHECK_EQUAL( + derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "[ALL] " + pubKey, + ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "[NONE] " + pubKey, + ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "[SINGLE] " + pubKey, + ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "[ALL|ANYONECANPAY] " + pubKey, + ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "[NONE|ANYONECANPAY] " + pubKey, + ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "[SINGLE|ANYONECANPAY] " + pubKey, + ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey, true)); + + BOOST_CHECK_EQUAL( + derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey)); + BOOST_CHECK_EQUAL( + derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey)); + BOOST_CHECK_EQUAL( + derSig + "01 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey)); + BOOST_CHECK_EQUAL( + derSig + "02 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey)); + BOOST_CHECK_EQUAL( + derSig + "03 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey)); + BOOST_CHECK_EQUAL( + derSig + "81 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey)); + BOOST_CHECK_EQUAL( + derSig + "82 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey)); + BOOST_CHECK_EQUAL( + derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey)); +} + +static CScript ScriptFromHex(const char *hex) +{ + std::vector data = ParseHex(hex); + return CScript(data.begin(), data.end()); +} + + +BOOST_AUTO_TEST_CASE(script_FindAndDelete) +{ + // Exercise the FindAndDelete functionality + CScript s; + CScript d; + CScript expect; + + s = CScript() << OP_1 << OP_2; + d = CScript(); // delete nothing should be a no-op + expect = s; + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); + BOOST_CHECK(s == expect); + + s = CScript() << OP_1 << OP_2 << OP_3; + d = CScript() << OP_2; + expect = CScript() << OP_1 << OP_3; + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); + + s = CScript() << OP_3 << OP_1 << OP_3 << OP_3 << OP_4 << OP_3; + d = CScript() << OP_3; + expect = CScript() << OP_1 << OP_4; + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 4); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("0302ff03"); // PUSH 0x02ff03 onto stack + d = ScriptFromHex("0302ff03"); + expect = CScript(); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("0302ff030302ff03"); // PUSH 0x2ff03 PUSH 0x2ff03 + d = ScriptFromHex("0302ff03"); + expect = CScript(); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("0302ff030302ff03"); + d = ScriptFromHex("02"); + expect = s; // FindAndDelete matches entire opcodes + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("0302ff030302ff03"); + d = ScriptFromHex("ff"); + expect = s; + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); + BOOST_CHECK(s == expect); + + // This is an odd edge case: strip of the push-three-bytes + // prefix, leaving 02ff03 which is push-two-bytes: + s = ScriptFromHex("0302ff030302ff03"); + d = ScriptFromHex("03"); + expect = CScript() << ParseHex("ff03") << ParseHex("ff03"); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); + BOOST_CHECK(s == expect); + + // Byte sequence that spans multiple opcodes: + s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY + d = ScriptFromHex("feed51"); + expect = s; + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); // doesn't match 'inside' opcodes + BOOST_CHECK(s == expect); + + s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY + d = ScriptFromHex("02feed51"); + expect = ScriptFromHex("69"); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("516902feed5169"); + d = ScriptFromHex("feed51"); + expect = s; + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("516902feed5169"); + d = ScriptFromHex("02feed51"); + expect = ScriptFromHex("516969"); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); + + s = CScript() << OP_0 << OP_0 << OP_1 << OP_1; + d = CScript() << OP_0 << OP_1; + expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); + + s = CScript() << OP_0 << OP_0 << OP_1 << OP_0 << OP_1 << OP_1; + d = CScript() << OP_0 << OP_1; + expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); + BOOST_CHECK(s == expect); + + // Another weird edge case: + // End with invalid push (not enough data)... + s = ScriptFromHex("0003feed"); + d = ScriptFromHex("03feed"); // ... can remove the invalid push + expect = ScriptFromHex("00"); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("0003feed"); + d = ScriptFromHex("00"); + expect = ScriptFromHex("03feed"); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/scriptnum10.h b/src/test/scriptnum10.h new file mode 100644 index 00000000..c88b8173 --- /dev/null +++ b/src/test/scriptnum10.h @@ -0,0 +1,176 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_TEST_SCRIPTNUM10_H +#define BITCOIN_TEST_SCRIPTNUM10_H + +#include "assert.h" +#include +#include +#include +#include +#include +#include + +class scriptnum10_error : public std::runtime_error +{ +public: + explicit scriptnum10_error(const std::string &str) : std::runtime_error(str) {} +}; + +class CScriptNum10 +{ + /** + * The ScriptNum implementation from Bitcoin Unlimited 0.10.0, for cross-comparison. + */ +public: + explicit CScriptNum10(const int64_t &n) { m_value = n; } + static const size_t nDefaultMaxNumSize = 4; + + explicit CScriptNum10(const std::vector &vch, + bool fRequireMinimal, + const size_t nMaxNumSize = nDefaultMaxNumSize) + { + if (vch.size() > nMaxNumSize) + { + throw scriptnum10_error("script number overflow"); + } + if (fRequireMinimal && vch.size() > 0) + { + // Check that the number is encoded with the minimum possible + // number of bytes. + // + // If the most-significant-byte - excluding the sign bit - is zero + // then we're not minimal. Note how this test also rejects the + // negative-zero encoding, 0x80. + if ((vch.back() & 0x7f) == 0) + { + // One exception: if there's more than one byte and the most + // significant bit of the second-most-significant-byte is set + // it would conflict with the sign bit. An example of this case + // is +-255, which encode to 0xff00 and 0xff80 respectively. + // (big-endian). + if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) + { + throw scriptnum10_error("non-minimally encoded script number"); + } + } + } + m_value = set_vch(vch); + } + + inline bool operator==(const int64_t &rhs) const { return m_value == rhs; } + inline bool operator!=(const int64_t &rhs) const { return m_value != rhs; } + inline bool operator<=(const int64_t &rhs) const { return m_value <= rhs; } + inline bool operator<(const int64_t &rhs) const { return m_value < rhs; } + inline bool operator>=(const int64_t &rhs) const { return m_value >= rhs; } + inline bool operator>(const int64_t &rhs) const { return m_value > rhs; } + inline bool operator==(const CScriptNum10 &rhs) const { return operator==(rhs.m_value); } + inline bool operator!=(const CScriptNum10 &rhs) const { return operator!=(rhs.m_value); } + inline bool operator<=(const CScriptNum10 &rhs) const { return operator<=(rhs.m_value); } + inline bool operator<(const CScriptNum10 &rhs) const { return operator<(rhs.m_value); } + inline bool operator>=(const CScriptNum10 &rhs) const { return operator>=(rhs.m_value); } + inline bool operator>(const CScriptNum10 &rhs) const { return operator>(rhs.m_value); } + inline CScriptNum10 operator+(const int64_t &rhs) const { return CScriptNum10(m_value + rhs); } + inline CScriptNum10 operator-(const int64_t &rhs) const { return CScriptNum10(m_value - rhs); } + inline CScriptNum10 operator+(const CScriptNum10 &rhs) const { return operator+(rhs.m_value); } + inline CScriptNum10 operator-(const CScriptNum10 &rhs) const { return operator-(rhs.m_value); } + inline CScriptNum10 &operator+=(const CScriptNum10 &rhs) { return operator+=(rhs.m_value); } + inline CScriptNum10 &operator-=(const CScriptNum10 &rhs) { return operator-=(rhs.m_value); } + inline CScriptNum10 operator-() const + { + assert(m_value != std::numeric_limits::min()); + return CScriptNum10(-m_value); + } + + inline CScriptNum10 &operator=(const int64_t &rhs) + { + m_value = rhs; + return *this; + } + + inline CScriptNum10 &operator+=(const int64_t &rhs) + { + assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits::max() - rhs) || + (rhs < 0 && m_value >= std::numeric_limits::min() - rhs)); + m_value += rhs; + return *this; + } + + inline CScriptNum10 &operator-=(const int64_t &rhs) + { + assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits::min() + rhs) || + (rhs < 0 && m_value <= std::numeric_limits::max() + rhs)); + m_value -= rhs; + return *this; + } + + int getint() const + { + if (m_value > std::numeric_limits::max()) + return std::numeric_limits::max(); + else if (m_value < std::numeric_limits::min()) + return std::numeric_limits::min(); + return m_value; + } + + std::vector getvch() const { return serialize(m_value); } + static std::vector serialize(const int64_t &value) + { + if (value == 0) + return std::vector(); + + std::vector result; + const bool neg = value < 0; + uint64_t absvalue = neg ? -value : value; + + while (absvalue) + { + result.push_back(absvalue & 0xff); + absvalue >>= 8; + } + + // - If the most significant byte is >= 0x80 and the value is positive, push a + // new zero-byte to make the significant byte < 0x80 again. + + // - If the most significant byte is >= 0x80 and the value is negative, push a + // new 0x80 byte that will be popped off when converting to an integral. + + // - If the most significant byte is < 0x80 and the value is negative, add + // 0x80 to it, since it will be subtracted and interpreted as a negative when + // converting to an integral. + + if (result.back() & 0x80) + result.push_back(neg ? 0x80 : 0); + else if (neg) + result.back() |= 0x80; + + return result; + } + +private: + static int64_t set_vch(const std::vector &vch) + { + if (vch.empty()) + return 0; + + int64_t result = 0; + for (size_t i = 0; i != vch.size(); ++i) + result |= static_cast(vch[i]) << 8 * i; + + // If the input vector's most significant byte is 0x80, remove it from + // the result's msb and return a negative. + if (vch.back() & 0x80) + return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1))))); + + return result; + } + + int64_t m_value; +}; + + +#endif // BITCOIN_TEST_BIGNUM_H diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp new file mode 100644 index 00000000..15bd180e --- /dev/null +++ b/src/test/scriptnum_tests.cpp @@ -0,0 +1,207 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "script/script.h" +#include "scriptnum10.h" +#include "test/test_bitcoin.h" + +#include +#include +#include + +BOOST_FIXTURE_TEST_SUITE(scriptnum_tests, BasicTestingSetup) + +/** A selection of numbers that do not trigger int64_t overflow + * when added/subtracted. */ +static const int64_t values[] = {0, 1, -2, 127, 128, -255, 256, (1LL << 15) - 1, -(1LL << 16), (1LL << 24) - 1, + (1LL << 31), 1 - (1LL << 32), 1LL << 40}; + +static const int64_t offsets[] = {1, 0x79, 0x80, 0x81, 0xFF, 0x7FFF, 0x8000, 0xFFFF, 0x10000}; + +static bool verify(const CScriptNum10 &bignum, const CScriptNum &scriptnum) +{ + return bignum.getvch() == scriptnum.getvch() && bignum.getint() == scriptnum.getint(); +} + +static void CheckCreateVch(const int64_t &num) +{ + CScriptNum10 bignum(num); + CScriptNum scriptnum(num); + BOOST_CHECK(verify(bignum, scriptnum)); + + std::vector vch = bignum.getvch(); + + CScriptNum10 bignum2(bignum.getvch(), false); + vch = scriptnum.getvch(); + CScriptNum scriptnum2(scriptnum.getvch(), false); + BOOST_CHECK(verify(bignum2, scriptnum2)); + + CScriptNum10 bignum3(scriptnum2.getvch(), false); + CScriptNum scriptnum3(bignum2.getvch(), false); + BOOST_CHECK(verify(bignum3, scriptnum3)); +} + +static void CheckCreateInt(const int64_t &num) +{ + CScriptNum10 bignum(num); + CScriptNum scriptnum(num); + BOOST_CHECK(verify(bignum, scriptnum)); + BOOST_CHECK(verify(CScriptNum10(bignum.getint()), CScriptNum(scriptnum.getint()))); + BOOST_CHECK(verify(CScriptNum10(scriptnum.getint()), CScriptNum(bignum.getint()))); + BOOST_CHECK(verify( + CScriptNum10(CScriptNum10(scriptnum.getint()).getint()), CScriptNum(CScriptNum(bignum.getint()).getint()))); +} + + +static void CheckAdd(const int64_t &num1, const int64_t &num2) +{ + const CScriptNum10 bignum1(num1); + const CScriptNum10 bignum2(num2); + const CScriptNum scriptnum1(num1); + const CScriptNum scriptnum2(num2); + CScriptNum10 bignum3(num1); + CScriptNum10 bignum4(num1); + CScriptNum scriptnum3(num1); + CScriptNum scriptnum4(num1); + + // int64_t overflow is undefined. + bool invalid = (((num2 > 0) && (num1 > (std::numeric_limits::max() - num2))) || + ((num2 < 0) && (num1 < (std::numeric_limits::min() - num2)))); + if (!invalid) + { + BOOST_CHECK(verify(bignum1 + bignum2, scriptnum1 + scriptnum2)); + BOOST_CHECK(verify(bignum1 + bignum2, scriptnum1 + num2)); + BOOST_CHECK(verify(bignum1 + bignum2, scriptnum2 + num1)); + } +} + +static void CheckNegate(const int64_t &num) +{ + const CScriptNum10 bignum(num); + const CScriptNum scriptnum(num); + + // -INT64_MIN is undefined + if (num != std::numeric_limits::min()) + BOOST_CHECK(verify(-bignum, -scriptnum)); +} + +static void CheckSubtract(const int64_t &num1, const int64_t &num2) +{ + const CScriptNum10 bignum1(num1); + const CScriptNum10 bignum2(num2); + const CScriptNum scriptnum1(num1); + const CScriptNum scriptnum2(num2); + bool invalid = false; + + // int64_t overflow is undefined. + invalid = ((num2 > 0 && num1 < std::numeric_limits::min() + num2) || + (num2 < 0 && num1 > std::numeric_limits::max() + num2)); + if (!invalid) + { + BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - scriptnum2)); + BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - num2)); + } + + invalid = ((num1 > 0 && num2 < std::numeric_limits::min() + num1) || + (num1 < 0 && num2 > std::numeric_limits::max() + num1)); + if (!invalid) + { + BOOST_CHECK(verify(bignum2 - bignum1, scriptnum2 - scriptnum1)); + BOOST_CHECK(verify(bignum2 - bignum1, scriptnum2 - num1)); + } +} + +static void CheckCompare(const int64_t &num1, const int64_t &num2) +{ + const CScriptNum10 bignum1(num1); + const CScriptNum10 bignum2(num2); + const CScriptNum scriptnum1(num1); + const CScriptNum scriptnum2(num2); + + BOOST_CHECK((bignum1 == bignum1) == (scriptnum1 == scriptnum1)); + BOOST_CHECK((bignum1 != bignum1) == (scriptnum1 != scriptnum1)); + BOOST_CHECK((bignum1 < bignum1) == (scriptnum1 < scriptnum1)); + BOOST_CHECK((bignum1 > bignum1) == (scriptnum1 > scriptnum1)); + BOOST_CHECK((bignum1 >= bignum1) == (scriptnum1 >= scriptnum1)); + BOOST_CHECK((bignum1 <= bignum1) == (scriptnum1 <= scriptnum1)); + + BOOST_CHECK((bignum1 == bignum1) == (scriptnum1 == num1)); + BOOST_CHECK((bignum1 != bignum1) == (scriptnum1 != num1)); + BOOST_CHECK((bignum1 < bignum1) == (scriptnum1 < num1)); + BOOST_CHECK((bignum1 > bignum1) == (scriptnum1 > num1)); + BOOST_CHECK((bignum1 >= bignum1) == (scriptnum1 >= num1)); + BOOST_CHECK((bignum1 <= bignum1) == (scriptnum1 <= num1)); + + BOOST_CHECK((bignum1 == bignum2) == (scriptnum1 == scriptnum2)); + BOOST_CHECK((bignum1 != bignum2) == (scriptnum1 != scriptnum2)); + BOOST_CHECK((bignum1 < bignum2) == (scriptnum1 < scriptnum2)); + BOOST_CHECK((bignum1 > bignum2) == (scriptnum1 > scriptnum2)); + BOOST_CHECK((bignum1 >= bignum2) == (scriptnum1 >= scriptnum2)); + BOOST_CHECK((bignum1 <= bignum2) == (scriptnum1 <= scriptnum2)); + + BOOST_CHECK((bignum1 == bignum2) == (scriptnum1 == num2)); + BOOST_CHECK((bignum1 != bignum2) == (scriptnum1 != num2)); + BOOST_CHECK((bignum1 < bignum2) == (scriptnum1 < num2)); + BOOST_CHECK((bignum1 > bignum2) == (scriptnum1 > num2)); + BOOST_CHECK((bignum1 >= bignum2) == (scriptnum1 >= num2)); + BOOST_CHECK((bignum1 <= bignum2) == (scriptnum1 <= num2)); +} + +static void RunCreate(const int64_t &num) +{ + CheckCreateInt(num); + CScriptNum scriptnum(num); + if (scriptnum.getvch().size() <= CScriptNum::nDefaultMaxNumSize) + CheckCreateVch(num); + else + { + BOOST_CHECK_THROW(CheckCreateVch(num), scriptnum10_error); + } +} + +static void RunOperators(const int64_t &num1, const int64_t &num2) +{ + CheckAdd(num1, num2); + CheckSubtract(num1, num2); + CheckNegate(num1); + CheckCompare(num1, num2); +} + +BOOST_AUTO_TEST_CASE(creation) +{ + for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); ++i) + { + for (size_t j = 0; j < sizeof(offsets) / sizeof(offsets[0]); ++j) + { + RunCreate(values[i]); + RunCreate(values[i] + offsets[j]); + RunCreate(values[i] - offsets[j]); + } + } +} + +BOOST_AUTO_TEST_CASE(operators) +{ + for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); ++i) + { + for (size_t j = 0; j < sizeof(offsets) / sizeof(offsets[0]); ++j) + { + RunOperators(values[i], values[i]); + RunOperators(values[i], -values[i]); + RunOperators(values[i], values[j]); + RunOperators(values[i], -values[j]); + RunOperators(values[i] + values[j], values[j]); + RunOperators(values[i] + values[j], -values[j]); + RunOperators(values[i] - values[j], values[j]); + RunOperators(values[i] - values[j], -values[j]); + RunOperators(values[i] + values[j], values[i] + values[j]); + RunOperators(values[i] + values[j], values[i] - values[j]); + RunOperators(values[i] - values[j], values[i] + values[j]); + RunOperators(values[i] - values[j], values[i] - values[j]); + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp new file mode 100644 index 00000000..a1772171 --- /dev/null +++ b/src/test/serialize_tests.cpp @@ -0,0 +1,344 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "serialize.h" +#include "hash.h" +#include "streams.h" +#include "test/test_bitcoin.h" + +#include + +#include + +using namespace std; + +BOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup) + +class CSerializeMethodsTestSingle +{ +protected: + int intval; + bool boolval; + std::string stringval; + const char *charstrval; + CTransaction txval; + +public: + CSerializeMethodsTestSingle() = default; + CSerializeMethodsTestSingle(int intvalin, + bool boolvalin, + std::string stringvalin, + const char *charstrvalin, + CTransaction txvalin) + : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), charstrval(charstrvalin), + txval(txvalin) + { + } + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream &s, Operation ser_action) + { + READWRITE(intval); + READWRITE(boolval); + READWRITE(stringval); + READWRITE(FLATDATA(charstrval)); + READWRITE(txval); + } + + bool operator==(const CSerializeMethodsTestSingle &rhs) + { + return intval == rhs.intval && boolval == rhs.boolval && stringval == rhs.stringval && + strcmp(charstrval, rhs.charstrval) == 0 && txval == rhs.txval; + } +}; + +class CSerializeMethodsTestMany : public CSerializeMethodsTestSingle +{ +public: + using CSerializeMethodsTestSingle::CSerializeMethodsTestSingle; + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream &s, Operation ser_action) + { + READWRITEMANY(intval, boolval, stringval, FLATDATA(charstrval), txval); + } +}; + +BOOST_AUTO_TEST_CASE(sizes) +{ + BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(char(0), 0)); + BOOST_CHECK_EQUAL(sizeof(int8_t), GetSerializeSize(int8_t(0), 0)); + BOOST_CHECK_EQUAL(sizeof(uint8_t), GetSerializeSize(uint8_t(0), 0)); + BOOST_CHECK_EQUAL(sizeof(int16_t), GetSerializeSize(int16_t(0), 0)); + BOOST_CHECK_EQUAL(sizeof(uint16_t), GetSerializeSize(uint16_t(0), 0)); + BOOST_CHECK_EQUAL(sizeof(int32_t), GetSerializeSize(int32_t(0), 0)); + BOOST_CHECK_EQUAL(sizeof(uint32_t), GetSerializeSize(uint32_t(0), 0)); + BOOST_CHECK_EQUAL(sizeof(int64_t), GetSerializeSize(int64_t(0), 0)); + BOOST_CHECK_EQUAL(sizeof(uint64_t), GetSerializeSize(uint64_t(0), 0)); + BOOST_CHECK_EQUAL(sizeof(float), GetSerializeSize(float(0), 0)); + BOOST_CHECK_EQUAL(sizeof(double), GetSerializeSize(double(0), 0)); + // Bool is serialized as char + BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(bool(0), 0)); + + // Sanity-check GetSerializeSize and c++ type matching + BOOST_CHECK_EQUAL(GetSerializeSize(char(0), 0), 1); + BOOST_CHECK_EQUAL(GetSerializeSize(int8_t(0), 0), 1); + BOOST_CHECK_EQUAL(GetSerializeSize(uint8_t(0), 0), 1); + BOOST_CHECK_EQUAL(GetSerializeSize(int16_t(0), 0), 2); + BOOST_CHECK_EQUAL(GetSerializeSize(uint16_t(0), 0), 2); + BOOST_CHECK_EQUAL(GetSerializeSize(int32_t(0), 0), 4); + BOOST_CHECK_EQUAL(GetSerializeSize(uint32_t(0), 0), 4); + BOOST_CHECK_EQUAL(GetSerializeSize(int64_t(0), 0), 8); + BOOST_CHECK_EQUAL(GetSerializeSize(uint64_t(0), 0), 8); + BOOST_CHECK_EQUAL(GetSerializeSize(float(0), 0), 4); + BOOST_CHECK_EQUAL(GetSerializeSize(double(0), 0), 8); + BOOST_CHECK_EQUAL(GetSerializeSize(bool(0), 0), 1); +} + +BOOST_AUTO_TEST_CASE(floats_conversion) +{ + // Choose values that map unambigiously to binary floating point to avoid + // rounding issues at the compiler side. + BOOST_CHECK_EQUAL(ser_uint32_to_float(0x00000000), 0.0F); + BOOST_CHECK_EQUAL(ser_uint32_to_float(0x3f000000), 0.5F); + BOOST_CHECK_EQUAL(ser_uint32_to_float(0x3f800000), 1.0F); + BOOST_CHECK_EQUAL(ser_uint32_to_float(0x40000000), 2.0F); + BOOST_CHECK_EQUAL(ser_uint32_to_float(0x40800000), 4.0F); + BOOST_CHECK_EQUAL(ser_uint32_to_float(0x44444444), 785.066650390625F); + + BOOST_CHECK_EQUAL(ser_float_to_uint32(0.0F), 0x00000000); + BOOST_CHECK_EQUAL(ser_float_to_uint32(0.5F), 0x3f000000); + BOOST_CHECK_EQUAL(ser_float_to_uint32(1.0F), 0x3f800000); + BOOST_CHECK_EQUAL(ser_float_to_uint32(2.0F), 0x40000000); + BOOST_CHECK_EQUAL(ser_float_to_uint32(4.0F), 0x40800000); + BOOST_CHECK_EQUAL(ser_float_to_uint32(785.066650390625F), 0x44444444); +} + +BOOST_AUTO_TEST_CASE(doubles_conversion) +{ + // Choose values that map unambigiously to binary floating point to avoid + // rounding issues at the compiler side. + BOOST_CHECK_EQUAL(ser_uint64_to_double(0x0000000000000000ULL), 0.0); + BOOST_CHECK_EQUAL(ser_uint64_to_double(0x3fe0000000000000ULL), 0.5); + BOOST_CHECK_EQUAL(ser_uint64_to_double(0x3ff0000000000000ULL), 1.0); + BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4000000000000000ULL), 2.0); + BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4010000000000000ULL), 4.0); + BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4088888880000000ULL), 785.066650390625); + + BOOST_CHECK_EQUAL(ser_double_to_uint64(0.0), 0x0000000000000000ULL); + BOOST_CHECK_EQUAL(ser_double_to_uint64(0.5), 0x3fe0000000000000ULL); + BOOST_CHECK_EQUAL(ser_double_to_uint64(1.0), 0x3ff0000000000000ULL); + BOOST_CHECK_EQUAL(ser_double_to_uint64(2.0), 0x4000000000000000ULL); + BOOST_CHECK_EQUAL(ser_double_to_uint64(4.0), 0x4010000000000000ULL); + BOOST_CHECK_EQUAL(ser_double_to_uint64(785.066650390625), 0x4088888880000000ULL); +} +/* +Python code to generate the below hashes: + + def reversed_hex(x): + return binascii.hexlify(''.join(reversed(x))) + def dsha256(x): + return hashlib.sha256(hashlib.sha256(x).digest()).digest() + + reversed_hex(dsha256(''.join(struct.pack('> j; + BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i); + } +} + +BOOST_AUTO_TEST_CASE(doubles) +{ + CDataStream ss(SER_DISK, 0); + // encode + for (int i = 0; i < 1000; i++) + { + ss << double(i); + } + BOOST_CHECK( + Hash(ss.begin(), ss.end()) == uint256S("43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96")); + + // decode + for (int i = 0; i < 1000; i++) + { + double j; + ss >> j; + BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i); + } +} + +BOOST_AUTO_TEST_CASE(varints) +{ + // encode + + CDataStream ss(SER_DISK, 0); + CDataStream::size_type size = 0; + for (int i = 0; i < 100000; i++) + { + ss << VARINT(i); + size += ::GetSerializeSize(VARINT(i), 0, 0); + BOOST_CHECK(size == ss.size()); + } + + for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) + { + ss << VARINT(i); + size += ::GetSerializeSize(VARINT(i), 0, 0); + BOOST_CHECK(size == ss.size()); + } + + // decode + for (int i = 0; i < 100000; i++) + { + int j = -1; + ss >> VARINT(j); + BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i); + } + + for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) + { + uint64_t j = -1; + ss >> VARINT(j); + BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i); + } +} + +BOOST_AUTO_TEST_CASE(compactsize) +{ + CDataStream ss(SER_DISK, 0); + vector::size_type i, j; + + for (i = 1; i <= MAX_SIZE; i *= 2) + { + WriteCompactSize(ss, i - 1); + WriteCompactSize(ss, i); + } + for (i = 1; i <= MAX_SIZE; i *= 2) + { + j = ReadCompactSize(ss); + BOOST_CHECK_MESSAGE((i - 1) == j, "decoded:" << j << " expected:" << (i - 1)); + j = ReadCompactSize(ss); + BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i); + } +} + +static bool isCanonicalException(const std::ios_base::failure &ex) +{ + std::ios_base::failure expectedException("non-canonical ReadCompactSize()"); + + // The string returned by what() can be different for different platforms. + // Instead of directly comparing the ex.what() with an expected string, + // create an instance of exception to see if ex.what() matches + // the expected explanatory string returned by the exception instance. + return strcmp(expectedException.what(), ex.what()) == 0; +} + + +BOOST_AUTO_TEST_CASE(noncanonical) +{ + // Write some non-canonical CompactSize encodings, and + // make sure an exception is thrown when read back. + CDataStream ss(SER_DISK, 0); + vector::size_type n; + + // zero encoded with three bytes: + ss.write("\xfd\x00\x00", 3); + BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); + + // 0xfc encoded with three bytes: + ss.write("\xfd\xfc\x00", 3); + BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); + + // 0xfd encoded with three bytes is OK: + ss.write("\xfd\xfd\x00", 3); + n = ReadCompactSize(ss); + BOOST_CHECK(n == 0xfd); + + // zero encoded with five bytes: + ss.write("\xfe\x00\x00\x00\x00", 5); + BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); + + // 0xffff encoded with five bytes: + ss.write("\xfe\xff\xff\x00\x00", 5); + BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); + + // zero encoded with nine bytes: + ss.write("\xff\x00\x00\x00\x00\x00\x00\x00\x00", 9); + BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); + + // 0x01ffffff encoded with nine bytes: + ss.write("\xff\xff\xff\xff\x01\x00\x00\x00\x00", 9); + BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); +} + +BOOST_AUTO_TEST_CASE(insert_delete) +{ + // Test inserting/deleting bytes. + CDataStream ss(SER_DISK, 0); + BOOST_CHECK_EQUAL(ss.size(), 0); + + ss.write("\x00\x01\x02\xff", 4); + BOOST_CHECK_EQUAL(ss.size(), 4); + + char c = (char)11; + + // Inserting at beginning/end/middle: + ss.insert(ss.begin(), c); + BOOST_CHECK_EQUAL(ss.size(), 5); + BOOST_CHECK_EQUAL(ss[0], c); + BOOST_CHECK_EQUAL(ss[1], 0); + + ss.insert(ss.end(), c); + BOOST_CHECK_EQUAL(ss.size(), 6); + BOOST_CHECK_EQUAL(ss[4], (char)0xff); + BOOST_CHECK_EQUAL(ss[5], c); + + ss.insert(ss.begin() + 2, c); + BOOST_CHECK_EQUAL(ss.size(), 7); + BOOST_CHECK_EQUAL(ss[2], c); + + // Delete at beginning/end/middle + ss.erase(ss.begin()); + BOOST_CHECK_EQUAL(ss.size(), 6); + BOOST_CHECK_EQUAL(ss[0], 0); + + ss.erase(ss.begin() + ss.size() - 1); + BOOST_CHECK_EQUAL(ss.size(), 5); + BOOST_CHECK_EQUAL(ss[4], (char)0xff); + + ss.erase(ss.begin() + 1); + BOOST_CHECK_EQUAL(ss.size(), 4); + BOOST_CHECK_EQUAL(ss[0], 0); + BOOST_CHECK_EQUAL(ss[1], 1); + BOOST_CHECK_EQUAL(ss[2], 2); + BOOST_CHECK_EQUAL(ss[3], (char)0xff); + + // Make sure GetAndClear does the right thing: + CSerializeData d; + ss.GetAndClear(d); + BOOST_CHECK_EQUAL(ss.size(), 0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp new file mode 100644 index 00000000..078eec59 --- /dev/null +++ b/src/test/sighash_tests.cpp @@ -0,0 +1,233 @@ +// Copyright (c) 2013-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "consensus/validation.h" +#include "data/sighash.json.h" +#include "hash.h" +#include "main.h" // For CheckTransaction +#include "random.h" +#include "script/interpreter.h" +#include "script/script.h" +#include "serialize.h" +#include "streams.h" +#include "test/test_bitcoin.h" +#include "util.h" +#include "utilstrencodings.h" +#include "version.h" + +#include + +#include + +#include + +extern UniValue read_json(const std::string &jsondata); + +// Old script.cpp SignatureHash function +uint256 static SignatureHashOld(CScript scriptCode, const CTransaction &txTo, unsigned int nIn, int nHashType) +{ + static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); + if (nIn >= txTo.vin.size()) + { + printf("ERROR: SignatureHash(): nIn=%d out of range\n", nIn); + return one; + } + CMutableTransaction txTmp(txTo); + + // In case concatenating two scripts ends up with two codeseparators, + // or an extra one at the end, this prevents all those possible incompatibilities. + scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR)); + + // Blank out other inputs' signatures + for (unsigned int i = 0; i < txTmp.vin.size(); i++) + txTmp.vin[i].scriptSig = CScript(); + txTmp.vin[nIn].scriptSig = scriptCode; + + // Blank out some of the outputs + if ((nHashType & 0x1f) == SIGHASH_NONE) + { + // Wildcard payee + txTmp.vout.clear(); + + // Let the others update at will + for (unsigned int i = 0; i < txTmp.vin.size(); i++) + if (i != nIn) + txTmp.vin[i].nSequence = 0; + } + else if ((nHashType & 0x1f) == SIGHASH_SINGLE) + { + // Only lock-in the txout payee at same index as txin + unsigned int nOut = nIn; + if (nOut >= txTmp.vout.size()) + { + printf("ERROR: SignatureHash(): nOut=%d out of range\n", nOut); + return one; + } + txTmp.vout.resize(nOut + 1); + for (unsigned int i = 0; i < nOut; i++) + txTmp.vout[i].SetNull(); + + // Let the others update at will + for (unsigned int i = 0; i < txTmp.vin.size(); i++) + if (i != nIn) + txTmp.vin[i].nSequence = 0; + } + + // Blank out other inputs completely, not recommended for open transactions + if (nHashType & SIGHASH_ANYONECANPAY) + { + txTmp.vin[0] = txTmp.vin[nIn]; + txTmp.vin.resize(1); + } + + // Serialize and hash + CHashWriter ss(SER_GETHASH, 0); + ss << txTmp << nHashType; + return ss.GetHash(); +} + +void static RandomScript(CScript &script) +{ + static const opcodetype oplist[] = { + OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR}; + script = CScript(); + int ops = (insecure_rand() % 10); + for (int i = 0; i < ops; i++) + script << oplist[insecure_rand() % (sizeof(oplist) / sizeof(oplist[0]))]; +} + +void static RandomTransaction(CMutableTransaction &tx, bool fSingle) +{ + tx.nVersion = insecure_rand(); + tx.vin.clear(); + tx.vout.clear(); + tx.nLockTime = (insecure_rand() % 2) ? insecure_rand() : 0; + int ins = (insecure_rand() % 4) + 1; + int outs = fSingle ? ins : (insecure_rand() % 4) + 1; + for (int in = 0; in < ins; in++) + { + tx.vin.push_back(CTxIn()); + CTxIn &txin = tx.vin.back(); + txin.prevout.hash = GetRandHash(); + txin.prevout.n = insecure_rand() % 4; + RandomScript(txin.scriptSig); + txin.nSequence = (insecure_rand() % 2) ? insecure_rand() : (unsigned int)-1; + } + for (int out = 0; out < outs; out++) + { + tx.vout.push_back(CTxOut()); + CTxOut &txout = tx.vout.back(); + txout.nValue = insecure_rand() % 100000000; + RandomScript(txout.scriptPubKey); + } +} + +BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(sighash_test) +{ + seed_insecure_rand(false); + +#if defined(PRINT_SIGHASH_JSON) + std::cout << "[\n"; + std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n"; +#endif + int nRandomTests = 50000; + +#if defined(PRINT_SIGHASH_JSON) + nRandomTests = 500; +#endif + for (int i = 0; i < nRandomTests; i++) + { + int nHashType = insecure_rand(); + + // Clear forkid + nHashType &= ~SIGHASH_FORKID; + + CMutableTransaction txTo; + RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); + CScript scriptCode; + RandomScript(scriptCode); + int nIn = insecure_rand() % txTo.vin.size(); + + uint256 sh, sho; + sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType); + sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, 0); +#if defined(PRINT_SIGHASH_JSON) + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << txTo; + + std::cout << "\t[\""; + std::cout << HexStr(ss.begin(), ss.end()) << "\", \""; + std::cout << HexStr(scriptCode) << "\", "; + std::cout << nIn << ", "; + std::cout << nHashType << ", \""; + std::cout << sh.GetHex() << "\"]"; + if (i + 1 != nRandomTests) + { + std::cout << ","; + } + std::cout << "\n"; +#endif + BOOST_CHECK(sh == sho); + } +#if defined(PRINT_SIGHASH_JSON) + std::cout << "]\n"; +#endif +} + +// Goal: check that SignatureHash generates correct hash +BOOST_AUTO_TEST_CASE(sighash_from_data) +{ + UniValue tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash))); + + for (unsigned int idx = 0; idx < tests.size(); idx++) + { + UniValue test = tests[idx]; + std::string strTest = test.write(); + if (test.size() < 1) // Allow for extra stuff (useful for comments) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + if (test.size() == 1) + continue; // comment + + std::string raw_tx, raw_script, sigHashHex; + int nIn, nHashType; + uint256 sh; + CTransaction tx; + CScript scriptCode = CScript(); + + try + { + // deserialize test data + raw_tx = test[0].get_str(); + raw_script = test[1].get_str(); + nIn = test[2].get_int(); + nHashType = test[3].get_int(); + sigHashHex = test[4].get_str(); + + CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION); + stream >> tx; + + CValidationState state; + BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest); + BOOST_CHECK(state.IsValid()); + + std::vector raw = ParseHex(raw_script); + scriptCode.insert(scriptCode.end(), raw.begin(), raw.end()); + } + catch (...) + { + BOOST_ERROR("Bad test, couldn't deserialize data: " << strTest); + continue; + } + + sh = SignatureHash(scriptCode, tx, nIn, nHashType, 0, 0); + BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); + } +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index a32a9534..13a8e86e 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -1,59 +1,68 @@ -#include -#include +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "script.h" #include "key.h" +#include "pubkey.h" +#include "script/script.h" +#include "script/standard.h" +#include "test/test_bitcoin.h" +#include "uint256.h" + +#include + +#include +#include using namespace std; // Helpers: -static std::vector -Serialize(const CScript& s) +static std::vector Serialize(const CScript &s) { - std::vector sSerialized(s); + std::vector sSerialized(s.begin(), s.end()); return sSerialized; } -BOOST_AUTO_TEST_SUITE(sigopcount_tests) +BOOST_FIXTURE_TEST_SUITE(sigopcount_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(GetSigOpCount) { // Test CScript::GetSigOpCount() CScript s1; - BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 0); - BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 0); + BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 0U); + BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 0U); uint160 dummy; - s1 << OP_1 << dummy << dummy << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 2); + s1 << OP_1 << ToByteVector(dummy) << ToByteVector(dummy) << OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 2U); s1 << OP_IF << OP_CHECKSIG << OP_ENDIF; - BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3); - BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21); + BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3U); + BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21U); - CScript p2sh; - p2sh.SetDestination(s1.GetID()); + CScript p2sh = GetScriptForDestination(CScriptID(s1)); CScript scriptSig; scriptSig << OP_0 << Serialize(s1); - BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U); - std::vector keys; + std::vector keys; for (int i = 0; i < 3; i++) { CKey k; k.MakeNewKey(true); - keys.push_back(k); + keys.push_back(k.GetPubKey()); } - CScript s2; - s2.SetMultisig(1, keys); - BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3); - BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20); - - p2sh.SetDestination(s2.GetID()); - BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0); - BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0); + CScript s2 = GetScriptForMultisig(1, keys); + BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3U); + BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20U); + + p2sh = GetScriptForDestination(CScriptID(s2)); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0U); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0U); CScript scriptSig2; - scriptSig2 << OP_1 << dummy << dummy << Serialize(s2); - BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3); + scriptSig2 << OP_1 << ToByteVector(dummy) << ToByteVector(dummy) << Serialize(s2); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U); } + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp new file mode 100644 index 00000000..7217cf46 --- /dev/null +++ b/src/test/skiplist_tests.cpp @@ -0,0 +1,123 @@ +// Copyright (c) 2014-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited 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 "test/test_bitcoin.h" +#include "util.h" + +#include + +#include + +#define SKIPLIST_LENGTH 300000 + +BOOST_FIXTURE_TEST_SUITE(skiplist_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(skiplist_test) +{ + std::vector vIndex(SKIPLIST_LENGTH); + + for (int i = 0; i < SKIPLIST_LENGTH; i++) + { + vIndex[i].nHeight = i; + vIndex[i].pprev = (i == 0) ? NULL : &vIndex[i - 1]; + vIndex[i].BuildSkip(); + } + + for (int i = 0; i < SKIPLIST_LENGTH; i++) + { + if (i > 0) + { + if (vIndex[i].pskip != &vIndex[vIndex[i].pskip->nHeight]) // Skips logging if successful + BOOST_CHECK(vIndex[i].pskip == &vIndex[vIndex[i].pskip->nHeight]); + if (vIndex[i].pskip->nHeight >= i) + BOOST_CHECK(vIndex[i].pskip->nHeight < i); + } + else + { + BOOST_CHECK(vIndex[i].pskip == NULL); + } + } + + for (int i = 0; i < 1000; i++) + { + int from = insecure_rand() % (SKIPLIST_LENGTH - 1); + int to = insecure_rand() % (from + 1); + + BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]); + BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]); + BOOST_CHECK(vIndex[from].GetAncestor(0) == &vIndex[0]); + } +} + +BOOST_AUTO_TEST_CASE(getlocator_test) +{ + // Build a main chain 100000 blocks long. + std::vector vHashMain(100000); + std::vector vBlocksMain(100000); + for (unsigned int i = 0; i < vBlocksMain.size(); i++) + { + vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height, so we can quickly check the distances. + vBlocksMain[i].nHeight = i; + vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : NULL; + vBlocksMain[i].phashBlock = &vHashMain[i]; + vBlocksMain[i].BuildSkip(); + if ((int)UintToArith256(vBlocksMain[i].GetBlockHash()).GetLow64() != vBlocksMain[i].nHeight) + BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksMain[i].GetBlockHash()).GetLow64(), vBlocksMain[i].nHeight); + if (!(vBlocksMain[i].pprev == NULL || vBlocksMain[i].nHeight == vBlocksMain[i].pprev->nHeight + 1)) + BOOST_CHECK(vBlocksMain[i].pprev == NULL || vBlocksMain[i].nHeight == vBlocksMain[i].pprev->nHeight + 1); + } + + // Build a branch that splits off at block 49999, 50000 blocks long. + std::vector vHashSide(50000); + std::vector vBlocksSide(50000); + for (unsigned int i = 0; i < vBlocksSide.size(); i++) + { + // Add 1<<128 to the hashes, so GetLow64() still returns the height. + vHashSide[i] = ArithToUint256(i + 50000 + (arith_uint256(1) << 128)); + vBlocksSide[i].nHeight = i + 50000; + vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : &vBlocksMain[49999]; + vBlocksSide[i].phashBlock = &vHashSide[i]; + vBlocksSide[i].BuildSkip(); + if ((int)UintToArith256(vBlocksSide[i].GetBlockHash()).GetLow64() != vBlocksSide[i].nHeight) + BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksSide[i].GetBlockHash()).GetLow64(), vBlocksSide[i].nHeight); + if (!(vBlocksSide[i].pprev == NULL || vBlocksSide[i].nHeight == vBlocksSide[i].pprev->nHeight + 1)) + BOOST_CHECK(vBlocksSide[i].pprev == NULL || vBlocksSide[i].nHeight == vBlocksSide[i].pprev->nHeight + 1); + } + + // Build a CChain for the main branch. + CChain chain; + chain.SetTip(&vBlocksMain.back()); + + // Test 100 random starting points for locators. + for (int n = 0; n < 100; n++) + { + int r = insecure_rand() % 150000; + CBlockIndex *tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000]; + CBlockLocator locator = chain.GetLocator(tip); + + // The first result must be the block itself, the last one must be genesis. + BOOST_CHECK(locator.vHave.front() == tip->GetBlockHash()); + BOOST_CHECK(locator.vHave.back() == vBlocksMain[0].GetBlockHash()); + + // Entries 1 through 11 (inclusive) go back one step each. + for (unsigned int i = 1; i < 12 && i < locator.vHave.size() - 1; i++) + { + BOOST_CHECK_EQUAL(UintToArith256(locator.vHave[i]).GetLow64(), tip->nHeight - i); + } + + // The further ones (excluding the last one) go back with exponential steps. + unsigned int dist = 2; + for (unsigned int i = 12; i < locator.vHave.size() - 1; i++) + { + BOOST_CHECK_EQUAL( + UintToArith256(locator.vHave[i - 1]).GetLow64() - UintToArith256(locator.vHave[i]).GetLow64(), dist); + dist *= 2; + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/stat_tests.cpp b/src/test/stat_tests.cpp new file mode 100644 index 00000000..e94588d7 --- /dev/null +++ b/src/test/stat_tests.cpp @@ -0,0 +1,134 @@ +// Copyright (c) 2016-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "stat.h" +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(stat_tests, BasicTestingSetup) +BOOST_AUTO_TEST_CASE(stat_testvectors) +{ + // const int numMetrics = 5; + CStatHistory *s1 = new CStatHistory("s1"); + BOOST_CHECK((*s1)() == 0); + CStatHistory *s2 = new CStatHistory("s2", STAT_OP_AVE); + BOOST_CHECK((*s2)() == 0); + CStatHistory *s3 = new CStatHistory("s3", STAT_OP_MAX); + BOOST_CHECK((*s3)() == 0); + CStatHistory *s4 = new CStatHistory("s4", STAT_OP_MIN); + BOOST_CHECK((*s4)() == 0.0); + + CStatHistory > *s5 = new CStatHistory >("s5"); + + (*s5) += 4.5f; + BOOST_CHECK((*s5)().min == 4.5f); + BOOST_CHECK((*s5)().max == 4.5f); + BOOST_CHECK((*s5)().val == 4.5f); + (*s5) << 1.5f; + BOOST_CHECK((*s5)().min == 4.5f); + BOOST_CHECK((*s5)().max == 6.0f); + BOOST_CHECK((*s5)().val == 6.0f); + + // check the + over various data types + (*s1) += 5; + BOOST_CHECK((*s1)() == 5); + (*s2) += 10; + BOOST_CHECK((*s2)() == 10); + (*s3) += 10000; + BOOST_CHECK((*s3)() == 10000); + (*s4) += 3.3; + BOOST_CHECK((*s4)() == 3.3); + + (*s1) += 15; + BOOST_CHECK((*s1)() == 20); + (*s2) += 110; + BOOST_CHECK((*s2)() == 120); + (*s3) += 110000; + BOOST_CHECK((*s3)() == 120000); + (*s4) += 4.3; + BOOST_CHECK((*s4)() == 7.6); + + // Make the boost callback huge so it never happens. I call timeout myself + statMinInterval = std::chrono::milliseconds(5000); + + s1->timeout(boost::system::error_code()); + s2->timeout(boost::system::error_code()); + s3->timeout(boost::system::error_code()); + s4->timeout(boost::system::error_code()); + s5->timeout(boost::system::error_code()); + + BOOST_CHECK((*s1)() == 0); + for (int i = 0; i < 30; i++) + { + (*s1) += 5; + (*s2) += 10; + (*s3) += 10000; + (*s4) += 3.3; + (*s5) << 2.4; + s1->timeout(boost::system::error_code()); + s2->timeout(boost::system::error_code()); + s3->timeout(boost::system::error_code()); + s4->timeout(boost::system::error_code()); + s5->timeout(boost::system::error_code()); + } + BOOST_CHECK(s1->History(1, 0) == 29 * 5 + 20); + BOOST_CHECK(s2->History(1, 0) == (29 * 10 + 120) / 30); + BOOST_CHECK(s3->History(1, 0) == 120000); + BOOST_CHECK(s4->History(1, 0) == 3.3); + + // statMinInterval=std::chrono::milliseconds(30); // Speed things up + for (int i = 0; i < 12; i++) + for (int j = 0; j < 30; j++) + { + (*s1) += 5; + (*s2) += 10; + (*s3) += 10000; + (*s4) += 3.3; + (*s5) << 2.4; + s1->timeout(boost::system::error_code()); + s2->timeout(boost::system::error_code()); + s3->timeout(boost::system::error_code()); + s4->timeout(boost::system::error_code()); + s5->timeout(boost::system::error_code()); + } + BOOST_CHECK(s1->History(2, 0) > 0); + BOOST_CHECK(s2->History(2, 0) > 0); + BOOST_CHECK(s3->History(2, 0) == 120000); + BOOST_CHECK(s4->History(2, 0) == 3.3); + + int array[15]; + + BOOST_CHECK(s1->Series(0, array, 15) == 15); + for (int i = 0; i < 15; i++) + BOOST_CHECK(array[i] == 5); + + delete s1; + delete s2; + delete s3; + delete s4; + delete s5; +} + +BOOST_AUTO_TEST_CASE(stat_empty_construct) +{ + { + /*! Create non-zero CStatHistory object and destroy it again. + This hopefully primes the same memory for the test below to be + non-zero, so the (formerly) missing initialization can be caught. + */ + CStatHistory *stats = new CStatHistory("name"); + (*stats) += 0x5555555555555555UL; + BOOST_CHECK((*stats)() == 0x5555555555555555UL); + delete stats; + } + { + CStatHistory *stats = new CStatHistory(); + // check that default constructor zeroes as well + BOOST_CHECK((*stats)() == 0UL); + delete stats; + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp new file mode 100644 index 00000000..ec7492ae --- /dev/null +++ b/src/test/streams_tests.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "streams.h" +#include "support/allocators/zeroafterfree.h" +#include "test/test_bitcoin.h" + +#include +#include // for 'operator+=()' +#include + +using namespace std; +using namespace boost::assign; // bring 'operator+=()' into scope + +BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(streams_serializedata_xor) +{ + std::vector in; + std::vector expected_xor; + std::vector key; + CDataStream ds(in, 0, 0); + + // Degenerate case + + key += '\x00', '\x00'; + ds.Xor(key); + BOOST_CHECK_EQUAL(std::string(expected_xor.begin(), expected_xor.end()), std::string(ds.begin(), ds.end())); + + in += '\x0f', '\xf0'; + expected_xor += '\xf0', '\x0f'; + + // Single character key + + ds.clear(); + ds.insert(ds.begin(), in.begin(), in.end()); + key.clear(); + + key += '\xff'; + ds.Xor(key); + BOOST_CHECK_EQUAL(std::string(expected_xor.begin(), expected_xor.end()), std::string(ds.begin(), ds.end())); + + // Multi character key + + in.clear(); + expected_xor.clear(); + in += '\xf0', '\x0f'; + expected_xor += '\x0f', '\x00'; + + ds.clear(); + ds.insert(ds.begin(), in.begin(), in.end()); + + key.clear(); + key += '\xff', '\x0f'; + + ds.Xor(key); + BOOST_CHECK_EQUAL(std::string(expected_xor.begin(), expected_xor.end()), std::string(ds.begin(), ds.end())); +} + +BOOST_AUTO_TEST_CASE(streams) +{ + // Smallest possible example + CDataStream ssx(SER_DISK, CLIENT_VERSION); + BOOST_CHECK_EQUAL(HexStr(ssx.begin(), ssx.end()), ""); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index bcf09078..80026f57 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -1,44 +1,180 @@ +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #define BOOST_TEST_MODULE Bitcoin Test Suite -#include -#include "db.h" +#include "test_bitcoin.h" + +#include "chainparams.h" +#include "consensus/consensus.h" +#include "consensus/validation.h" +#include "crypto/sha256.h" +#include "fs.h" +#include "key.h" #include "main.h" -#include "wallet.h" +#include "miner.h" +#include "parallel.h" +#include "pubkey.h" +#include "random.h" +#include "rpc/register.h" +#include "rpc/server.h" +#include "test/testutil.h" +#include "txdb.h" +#include "txmempool.h" +#include "ui_interface.h" +#include +#include + +#include -CWallet* pwalletMain; -CClientUIInterface uiInterface; +#include + +CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h extern bool fPrintToConsole; extern void noui_connect(); -struct TestingSetup { - TestingSetup() { - fPrintToDebugger = true; // don't want to write to debug.log file - noui_connect(); - bitdb.MakeMock(); - LoadBlockIndex(true); - bool fFirstRun; - pwalletMain = new CWallet("wallet.dat"); - pwalletMain->LoadWallet(fFirstRun); - RegisterWallet(pwalletMain); - } - ~TestingSetup() +BasicTestingSetup::BasicTestingSetup(const std::string &chainName) +{ + SHA256AutoDetect(); + ECC_Start(); + SetupEnvironment(); + SetupNetworking(); + fPrintToDebugLog = false; // don't want to write to debug.log file + fCheckBlockIndex = true; + SelectParams(chainName); + noui_connect(); +} + +BasicTestingSetup::~BasicTestingSetup() { ECC_Stop(); } +TestingSetup::TestingSetup(const std::string &chainName) : BasicTestingSetup(chainName) +{ + const CChainParams &chainparams = Params(); + // Ideally we'd move all the RPC tests to the functional testing framework + // instead of unit tests, but for now we need these here. + RegisterAllCoreRPCCommands(tableRPC); + ClearDatadirCache(); + pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); + fs::create_directories(pathTemp); + pblocktree = new CBlockTreeDB(1 << 20, true); + pcoinsdbview = new CCoinsViewDB(1 << 23, true); + pcoinsTip = new CCoinsViewCache(pcoinsdbview); + bool worked = InitBlockIndex(chainparams); + assert(worked); + + PV.reset(new CParallelValidation(3, &threadGroup)); + RegisterNodeSignals(GetNodeSignals()); +} + +TestingSetup::~TestingSetup() +{ + UnregisterNodeSignals(GetNodeSignals()); + threadGroup.interrupt_all(); + threadGroup.join_all(); + UnloadBlockIndex(); + delete pcoinsTip; + delete pcoinsdbview; + delete pblocktree; + fs::remove_all(pathTemp); +} + +TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST) +{ + // Generate a 100-block chain: + coinbaseKey.MakeNewKey(true); + CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; + for (int i = 0; i < COINBASE_MATURITY; i++) { - delete pwalletMain; - pwalletMain = NULL; - bitdb.Flush(true); + std::vector noTxns; + CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey); + coinbaseTxns.push_back(b.vtx[0]); } -}; - -BOOST_GLOBAL_FIXTURE(TestingSetup); +} -void Shutdown(void* parg) +// +// Create a new block with just given transactions, coinbase paying to +// scriptPubKey, and try to add it to the current chain. +// +CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector &txns, + const CScript &scriptPubKey) { - exit(0); + const CChainParams &chainparams = Params(); + CBlockTemplate *pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); + CBlock &block = pblocktemplate->block; + + // Replace mempool-selected txns with just coinbase plus passed-in txns: + block.vtx.resize(1); + BOOST_FOREACH (const CMutableTransaction &tx, txns) + block.vtx.push_back(tx); + // IncrementExtraNonce creates a valid coinbase and merkleRoot + unsigned int extraNonce = 0; + IncrementExtraNonce(&block, extraNonce); + + while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) + ++block.nNonce; + + CValidationState state; + ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, false); + + CBlock result = block; + delete pblocktemplate; + return result; } -void StartShutdown() +TestChain100Setup::~TestChain100Setup() {} +CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPool *pool) { - exit(0); + CTransaction txn(tx); + bool hasNoDependencies = pool ? pool->HasNoInputsOf(tx) : hadNoDependencies; + // Hack to assume either its completely dependent on other mempool txs or not at all + CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0; + + return CTxMemPoolEntry( + txn, nFee, nTime, dPriority, nHeight, hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount, lp); } +void Shutdown(void *parg) { exit(0); } +void StartShutdown() { exit(0); } +bool ShutdownRequested() { return false; } +using namespace boost::program_options; + +struct StartupShutdown +{ + StartupShutdown() + { + options_description optDef("Options"); + optDef.add_options()("testhelp", "program options information")( + "log_level", "set boost logging (all, test_suite, message, warning, error, ...)")( + "log_bitcoin", value()->required(), "bitcoin logging destination (console, none)"); + variables_map opts; + store(parse_command_line(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv, optDef), + opts); + + if (opts.count("testhelp")) + { + std::cout << optDef << std::endl; + exit(0); + } + + if (opts.count("log_bitcoin")) + { + std::string s = opts["log_bitcoin"].as(); + if (s == "console") + { + fPrintToConsole = true; + fPrintToDebugLog = false; + } + else if (s == "none") + { + fPrintToConsole = false; + fPrintToDebugLog = false; + } + } + } + ~StartupShutdown() { UnlimitedCleanup(); } +}; + +BOOST_GLOBAL_FIXTURE(StartupShutdown); diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h new file mode 100644 index 00000000..6d87f1a5 --- /dev/null +++ b/src/test/test_bitcoin.h @@ -0,0 +1,118 @@ +#ifndef BITCOIN_TEST_TEST_BITCOIN_H +#define BITCOIN_TEST_TEST_BITCOIN_H + +#include "chainparamsbase.h" +#include "fs.h" +#include "key.h" +#include "pubkey.h" +#include "txdb.h" +#include "txmempool.h" + +#include + +/** Basic testing setup. + * This just configures logging and chain parameters. + */ +struct BasicTestingSetup +{ + ECCVerifyHandle globalVerifyHandle; + + BasicTestingSetup(const std::string &chainName = CBaseChainParams::MAIN); + ~BasicTestingSetup(); +}; + +/** Testing setup that configures a complete environment. + * Included are data directory, coins database, script check threads setup. + */ +struct TestingSetup : public BasicTestingSetup +{ + CCoinsViewDB *pcoinsdbview; + fs::path pathTemp; + boost::thread_group threadGroup; + + TestingSetup(const std::string &chainName = CBaseChainParams::MAIN); + ~TestingSetup(); +}; + +class CBlock; +struct CMutableTransaction; +class CScript; + +// +// Testing fixture that pre-creates a +// 100-block REGTEST-mode block chain +// +struct TestChain100Setup : public TestingSetup +{ + TestChain100Setup(); + + // Create a new block with just given transactions, coinbase paying to + // scriptPubKey, and try to add it to the current chain. + CBlock CreateAndProcessBlock(const std::vector &txns, const CScript &scriptPubKey); + + ~TestChain100Setup(); + + std::vector coinbaseTxns; // For convenience, coinbase transactions + CKey coinbaseKey; // private/public key needed to spend coinbase transactions +}; + +class CTxMemPoolEntry; +class CTxMemPool; + +struct TestMemPoolEntryHelper +{ + // Default values + CAmount nFee; + int64_t nTime; + double dPriority; + unsigned int nHeight; + 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) + { + } + + CTxMemPoolEntry FromTx(CMutableTransaction &tx, CTxMemPool *pool = NULL); + + // Change the default value + TestMemPoolEntryHelper &Fee(CAmount _fee) + { + nFee = _fee; + return *this; + } + TestMemPoolEntryHelper &Time(int64_t _time) + { + nTime = _time; + return *this; + } + TestMemPoolEntryHelper &Priority(double _priority) + { + dPriority = _priority; + return *this; + } + TestMemPoolEntryHelper &Height(unsigned int _height) + { + nHeight = _height; + return *this; + } + TestMemPoolEntryHelper &HadNoDependencies(bool _hnd) + { + hadNoDependencies = _hnd; + return *this; + } + TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) + { + spendsCoinbase = _flag; + return *this; + } + TestMemPoolEntryHelper &SigOps(unsigned int _sigops) + { + sigOpCount = _sigops; + return *this; + } +}; +#endif diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp new file mode 100644 index 00000000..d8a481a9 --- /dev/null +++ b/src/test/test_bitcoin_fuzzy.cpp @@ -0,0 +1,344 @@ +// 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. + +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + +#include "addrman.h" +#include "chain.h" +#include "coins.h" +#include "compressor.h" +#include "consensus/merkle.h" +#include "net.h" +#include "primitives/block.h" +#include "protocol.h" +#include "pubkey.h" +#include "script/script.h" +#include "streams.h" +#include "undo.h" +#include "version.h" + +#include +#include + +#include +#include + +enum TEST_ID +{ + CBLOCK_DESERIALIZE = 0, + CTRANSACTION_DESERIALIZE, + CBLOCKLOCATOR_DESERIALIZE, + CBLOCKMERKLEROOT, + CADDRMAN_DESERIALIZE, + CBLOCKHEADER_DESERIALIZE, + CBANENTRY_DESERIALIZE, + CTXUNDO_DESERIALIZE, + CBLOCKUNDO_DESERIALIZE, + CCOINS_DESERIALIZE, + CNETADDR_DESERIALIZE, + CSERVICE_DESERIALIZE, + CMESSAGEHEADER_DESERIALIZE, + CADDRESS_DESERIALIZE, + CINV_DESERIALIZE, + CBLOOMFILTER_DESERIALIZE, + CDISKBLOCKINDEX_DESERIALIZE, + CTXOUTCOMPRESSOR_DESERIALIZE, + TEST_ID_END +}; + +bool read_stdin(std::vector &data) +{ + char buffer[1024]; + ssize_t length = 0; + while ((length = read(STDIN_FILENO, buffer, 1024)) > 0) + { + data.insert(data.end(), buffer, buffer + length); + + if (data.size() > (1 << 20)) + return false; + } + return length == 0; +} + +int main(int argc, char **argv) +{ + ECCVerifyHandle globalVerifyHandle; + std::vector buffer; + if (!read_stdin(buffer)) + return 0; + + if (buffer.size() < sizeof(uint32_t)) + return 0; + + uint32_t test_id = 0xffffffff; + memcpy(&test_id, &buffer[0], sizeof(uint32_t)); + buffer.erase(buffer.begin(), buffer.begin() + sizeof(uint32_t)); + + if (test_id >= TEST_ID_END) + return 0; + + CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); + try + { + int nVersion; + ds >> nVersion; + ds.SetVersion(nVersion); + } + catch (const std::ios_base::failure &e) + { + return 0; + } + + switch (test_id) + { + case CBLOCK_DESERIALIZE: + { + try + { + CBlock block; + ds >> block; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CTRANSACTION_DESERIALIZE: + { + try + { + CTransaction tx; + ds >> tx; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CBLOCKLOCATOR_DESERIALIZE: + { + try + { + CBlockLocator bl; + ds >> bl; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CBLOCKMERKLEROOT: + { + try + { + CBlock block; + ds >> block; + bool mutated; + BlockMerkleRoot(block, &mutated); + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CADDRMAN_DESERIALIZE: + { + try + { + CAddrMan am; + ds >> am; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CBLOCKHEADER_DESERIALIZE: + { + try + { + CBlockHeader bh; + ds >> bh; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CBANENTRY_DESERIALIZE: + { + try + { + CBanEntry be; + ds >> be; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CTXUNDO_DESERIALIZE: + { + try + { + CTxUndo tu; + ds >> tu; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CBLOCKUNDO_DESERIALIZE: + { + try + { + CBlockUndo bu; + ds >> bu; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CCOINS_DESERIALIZE: + { + try + { + Coin coin; + ds >> coin; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CNETADDR_DESERIALIZE: + { + try + { + CNetAddr na; + ds >> na; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CSERVICE_DESERIALIZE: + { + try + { + CService s; + ds >> s; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CMESSAGEHEADER_DESERIALIZE: + { + CMessageHeader::MessageStartChars pchMessageStart = {0x00, 0x00, 0x00, 0x00}; + try + { + CMessageHeader mh(pchMessageStart); + ds >> mh; + if (!mh.IsValid(pchMessageStart)) + { + return 0; + } + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CADDRESS_DESERIALIZE: + { + try + { + CAddress a; + ds >> a; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CINV_DESERIALIZE: + { + try + { + CInv i; + ds >> i; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CBLOOMFILTER_DESERIALIZE: + { + try + { + CBloomFilter bf; + ds >> bf; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CDISKBLOCKINDEX_DESERIALIZE: + { + try + { + CDiskBlockIndex dbi; + ds >> dbi; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + break; + } + case CTXOUTCOMPRESSOR_DESERIALIZE: + { + CTxOut to; + CTxOutCompressor toc(to); + try + { + ds >> toc; + } + catch (const std::ios_base::failure &e) + { + return 0; + } + + break; + } + default: + return 0; + } + return 0; +} diff --git a/src/test/testutil.cpp b/src/test/testutil.cpp new file mode 100644 index 00000000..8057c5dd --- /dev/null +++ b/src/test/testutil.cpp @@ -0,0 +1,13 @@ +// 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 +#endif + +#include "fs.h" + +fs::path GetTempPath() { return fs::temp_directory_path(); } diff --git a/src/test/testutil.h b/src/test/testutil.h new file mode 100644 index 00000000..cbe784d6 --- /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 "fs.h" + +fs::path GetTempPath(); + +#endif // BITCOIN_TEST_TESTUTIL_H diff --git a/src/test/thinblock_data_tests.cpp b/src/test/thinblock_data_tests.cpp new file mode 100644 index 00000000..cb2ba456 --- /dev/null +++ b/src/test/thinblock_data_tests.cpp @@ -0,0 +1,215 @@ +// Copyright (c) 2013-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "thinblock.h" +#include "net.h" +#include "test/test_bitcoin.h" +#include +#include +#include +#include +#include +#include + +using namespace std; + +CService ipaddress3(uint32_t i, uint32_t port) +{ + struct in_addr s; + s.s_addr = i; + return CService(CNetAddr(s), port); +} + +class TestTBD : public CThinBlockData +{ +protected: + virtual int64_t getTimeForStats() { return times[min(times_idx++, times.size() - 1)]; } + vector times; + size_t times_idx; + +public: + TestTBD(const vector &_times) + { + assert(_times.size() > 0); + times = _times; + times_idx = 0; + } + void resetTimeIdx() { times_idx = 0; } +}; + + +BOOST_FIXTURE_TEST_SUITE(thinblock_data_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(test_thinblock_byte_tracking) +{ + CThinBlockData thindata; + + /** + * Do calcuations for single peer building a thinblock + */ + + CAddress addr1(ipaddress3(0xa0b0c001, 10000)); + CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + + thindata.ResetThinBlockBytes(); + BOOST_CHECK(0 == thindata.GetThinBlockBytes()); + BOOST_CHECK(0 == dummyNode1.nLocalThinBlockBytes); + + thindata.AddThinBlockBytes(0, &dummyNode1); + BOOST_CHECK(0 == thindata.GetThinBlockBytes()); + BOOST_CHECK(0 == dummyNode1.nLocalThinBlockBytes); + + thindata.AddThinBlockBytes(1000, &dummyNode1); + BOOST_CHECK(1000 == thindata.GetThinBlockBytes()); + BOOST_CHECK(1000 == dummyNode1.nLocalThinBlockBytes); + + thindata.AddThinBlockBytes(449932, &dummyNode1); + BOOST_CHECK(450932 == thindata.GetThinBlockBytes()); + BOOST_CHECK(450932 == dummyNode1.nLocalThinBlockBytes); + + thindata.DeleteThinBlockBytes(0, &dummyNode1); + BOOST_CHECK(450932 == thindata.GetThinBlockBytes()); + BOOST_CHECK(450932 == dummyNode1.nLocalThinBlockBytes); + + thindata.DeleteThinBlockBytes(1, &dummyNode1); + BOOST_CHECK(450931 == thindata.GetThinBlockBytes()); + BOOST_CHECK(450931 == dummyNode1.nLocalThinBlockBytes); + + thindata.DeleteThinBlockBytes(13939, &dummyNode1); + BOOST_CHECK(436992 == thindata.GetThinBlockBytes()); + BOOST_CHECK(436992 == dummyNode1.nLocalThinBlockBytes); + + // Try to delete more bytes than we already have tracked. This should not be possible...we don't allow this + // to happen in the event that we get an incorrect or invalid value returned for the dynamic memory usage of + // a transaction. This could then be used in a theoretical attack by resetting total byte usage to zero while + // continuing to build more thinblocks. + thindata.DeleteThinBlockBytes(436993, &dummyNode1); + BOOST_CHECK_MESSAGE(436992 == thindata.GetThinBlockBytes(), "nThinBlockBytes is " << thindata.GetThinBlockBytes()); + BOOST_CHECK_MESSAGE( + 436992 == dummyNode1.nLocalThinBlockBytes, "nLocalThinBlockBytes is " << dummyNode1.nLocalThinBlockBytes); + + + /** + * Add a second peer and do more calcuations for building a second thinblock + */ + + CAddress addr2(ipaddress3(0xa0b0c002, 10000)); + CNode dummyNode2(INVALID_SOCKET, addr2, "", true); + + thindata.AddThinBlockBytes(1000, &dummyNode2); + BOOST_CHECK(437992 == thindata.GetThinBlockBytes()); + BOOST_CHECK(436992 == dummyNode1.nLocalThinBlockBytes); + BOOST_CHECK(1000 == dummyNode2.nLocalThinBlockBytes); + + thindata.DeleteThinBlockBytes(0, &dummyNode2); + BOOST_CHECK(437992 == thindata.GetThinBlockBytes()); + BOOST_CHECK(1000 == dummyNode2.nLocalThinBlockBytes); + + thindata.DeleteThinBlockBytes(1, &dummyNode2); + BOOST_CHECK(437991 == thindata.GetThinBlockBytes()); + BOOST_CHECK(436992 == dummyNode1.nLocalThinBlockBytes); + BOOST_CHECK(999 == dummyNode2.nLocalThinBlockBytes); + + thindata.DeleteThinBlockBytes(999, &dummyNode2); + BOOST_CHECK(436992 == thindata.GetThinBlockBytes()); + BOOST_CHECK(436992 == dummyNode1.nLocalThinBlockBytes); + BOOST_CHECK(0 == dummyNode2.nLocalThinBlockBytes); + + // now finally reset everything + thindata.ResetThinBlockBytes(); + BOOST_CHECK_MESSAGE(0 == thindata.GetThinBlockBytes(), "nThinBlockBytes is " << thindata.GetThinBlockBytes()); +} + +BOOST_AUTO_TEST_CASE(test_thinblockdata_stats1) +{ + vector times1(1000); // minutes + + for (uint32_t i = 0; i < times1.size(); i++) + { + times1[i] = 1000 * 60 * i; + } + + { + TestTBD tbd(times1); + // exercise summary methods on empty arrays to make sure they don't fail + // in weird ways + tbd.ToString(); + tbd.InBoundPercentToString(); + tbd.OutBoundPercentToString(); + tbd.InBoundBloomFiltersToString(); + tbd.OutBoundBloomFiltersToString(); + tbd.ResponseTimeToString(); + tbd.ValidationTimeToString(); + tbd.ReRequestedTxToString(); + tbd.MempoolLimiterBytesSavedToString(); + tbd.GetThinBlockBytes(); + } + + { + TestTBD tbd(times1); + + for (int64_t i : boost::irange(0, 100)) + tbd.UpdateInBound(i, 3 * i); + + string res = tbd.InBoundPercentToString(); + + BOOST_CHECK_MESSAGE(res.find("66.7%") != string::npos, "InBoundPercentToString() is " << res); + } + + { + TestTBD tbd(times1); + + for (int64_t i : boost::irange(0, 100)) + tbd.UpdateOutBound(i, 3 * i); + + string res = tbd.OutBoundPercentToString(); + + BOOST_CHECK_MESSAGE(res.find("66.7%") != string::npos, "OutBoundPercentToString() is " << res); + } + + { + TestTBD tbd(times1); + + for (int64_t i : boost::irange(0, 100)) + tbd.UpdateInBoundBloomFilter(1000 * i); + + string res = tbd.InBoundBloomFiltersToString(); + + BOOST_CHECK_MESSAGE(res.find("49.50KB") != string::npos, "InBoundBloomFiltersToString() is " << res); + } + + { + TestTBD tbd(times1); + + for (int64_t i : boost::irange(0, 100)) + tbd.UpdateOutBoundBloomFilter(1000 * i); + + string res = tbd.OutBoundBloomFiltersToString(); + BOOST_CHECK_MESSAGE(res.find("49.50KB") != string::npos, "OutBoundBloomFiltersToString() is " << res); + } + // FIXME: check others somehow that depend on chain sync state + + { + TestTBD tbd(times1); + + for (int64_t i : boost::irange(0, 100)) + tbd.UpdateInBoundReRequestedTx(1000 * i); + + string res = tbd.ReRequestedTxToString(); + BOOST_CHECK_MESSAGE(res.find(":100") != string::npos, "ReRequestedTxToString() is " << res); + } + + { + TestTBD tbd(times1); + + for (int64_t i : boost::irange(0, 100)) + tbd.UpdateMempoolLimiterBytesSaved(1000 * i); + + string res = tbd.MempoolLimiterBytesSavedToString(); + BOOST_CHECK_MESSAGE(res.find("4.95MB") != string::npos, "MempoolLimiterBytesSavedToString() is " << res); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/thinblock_tests.cpp b/src/test/thinblock_tests.cpp new file mode 100644 index 00000000..47d16c48 --- /dev/null +++ b/src/test/thinblock_tests.cpp @@ -0,0 +1,194 @@ +// Copyright (c) 2016 Bitcoin Unlimited Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "thinblock.h" +#include "bloom.h" +#include "chainparams.h" +#include "main.h" +#include "primitives/block.h" +#include "random.h" +#include "serialize.h" +#include "streams.h" +#include "txmempool.h" +#include "uint256.h" +#include "unlimited.h" +#include "util.h" +#include "utilstrencodings.h" +#include "version.h" + +#include "test/test_bitcoin.h" + +#include +#include +#include + +CBlock TestBlock() +{ // Thanks dagurval :) + // Block taken from bloom_tests.cpp merkle_block_1 + // Random real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af) + // With 9 txes + CDataStream stream( + ParseHex( + "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c" + "3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000" + "000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc" + "8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00" + "000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab2" + "4889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c31" + "1b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac00" + "0000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268" + "ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc" + "597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e5" + "71fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a" + "0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac00000000010000" + "0002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e" + "5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe6" + "7512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf97584" + "5c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035d" + "defb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14" + "a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14c" + "a4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043" + "410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9" + "d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5" + "c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e" + "5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d7" + "89904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c0000000000" + "1976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb" + "042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a" + "4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987da" + "d92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3" + "cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a91455056148" + "59643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00" + "000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc" + "2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f" + "7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c6" + "9b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa" + "4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702" + "200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f" + "388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acf" + "cab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48" + "cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805" + "c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1" + "d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd20000" + "00008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae" + "2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07" + "d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc65" + "14edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558" + "165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3" + "a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8eb" + "bb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166" + "d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229ce" + "fc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b6" + "3f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a3316" + "1dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688" + "ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a905" + "9cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c35306" + "9e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c" + "79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce30" + "12e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c0000" + "0000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"), + SER_NETWORK, PROTOCOL_VERSION); + CBlock block; + stream >> block; + return block; +}; + +CService ipaddress2(uint32_t i, uint32_t port) +{ + struct in_addr s; + s.s_addr = i; + return CService(CNetAddr(s), port); +} + + +BOOST_FIXTURE_TEST_SUITE(thinblock_tests, TestingSetup) + +BOOST_AUTO_TEST_CASE(thinblock_test) +{ + CBloomFilter filter; + std::vector vOrphanHashes; + CAddress addr1(ipaddress2(0xa0b0c001, 10000)); + CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + + // Create 10 random hashes to seed the orphanhash vector. This way we will create a bloom filter + // with a size of 10 elements. + std::string hash = "3fba505b48865fccda4e248cecc39d5dfbc6b8ef7b4adc9cd27242c1193c714"; + for (int i = 0; i < 10; i++) + { + std::stringstream ss; + ss << i; + hash.append(ss.str()); + uint256 random_hash = uint256S(hash); + vOrphanHashes.push_back(random_hash); + } + BuildSeededBloomFilter(filter, vOrphanHashes, TestBlock().GetHash(), &dummyNode1, true); + + /* empty filter */ + CBlock block = TestBlock(); + CThinBlock thinblock(block, filter); + CXThinBlock xthinblock(block, &filter); + BOOST_CHECK_EQUAL(9, thinblock.vMissingTx.size()); + BOOST_CHECK_EQUAL(9, xthinblock.vMissingTx.size()); + + /* insert txid not in block */ + const uint256 random_hash = uint256S("3fba505b48865fccda4e248cecc39d5dfbc6b8ef7b4adc9cd27242c1193c7133"); + filter.insert(random_hash); + CThinBlock thinblock1(block, filter); + CXThinBlock xthinblock1(block, &filter); + BOOST_CHECK_EQUAL(9, thinblock1.vMissingTx.size()); + BOOST_CHECK_EQUAL(9, xthinblock1.vMissingTx.size()); + + /* insert txid in block */ + const uint256 hash_in_block = block.vtx[1].GetHash(); + filter.insert(hash_in_block); + CThinBlock thinblock2(block, filter); + CXThinBlock xthinblock2(block, &filter); + BOOST_CHECK_EQUAL(8, thinblock2.vMissingTx.size()); + BOOST_CHECK_EQUAL(8, xthinblock2.vMissingTx.size()); + + /*collision test*/ + BOOST_CHECK(!xthinblock2.collision); + block.vtx.push_back(block.vtx[1]); // duplicate tx + filter.clear(); + CXThinBlock xthinblock3(block, &filter); + BOOST_CHECK(xthinblock3.collision); + + + // Add tests using a non-deterministic bloom filter which may + // or may not yeild a false positive. + CBloomFilter filter1; + BuildSeededBloomFilter(filter1, vOrphanHashes, TestBlock().GetHash(), &dummyNode1, false); + + /* empty filter */ + CBlock block1 = TestBlock(); + CThinBlock thinblock4(block1, filter1); + CXThinBlock xthinblock4(block1, &filter1); + BOOST_CHECK(thinblock4.vMissingTx.size() >= 8 && thinblock4.vMissingTx.size() <= 9); + BOOST_CHECK(xthinblock4.vMissingTx.size() >= 8 && xthinblock4.vMissingTx.size() <= 9); + + /* insert txid not in block */ + const uint256 random_hash1 = uint256S("3fba505b48865fccda4e248cecc39d5dfbc6b8ef7b4adc9cd27242c1193c7132"); + filter1.insert(random_hash1); + CThinBlock thinblock5(block1, filter1); + CXThinBlock xthinblock5(block1, &filter1); + BOOST_CHECK(thinblock5.vMissingTx.size() >= 8 && thinblock5.vMissingTx.size() <= 9); + BOOST_CHECK(xthinblock5.vMissingTx.size() >= 8 && xthinblock5.vMissingTx.size() <= 9); + + /* insert txid in block */ + const uint256 hash_in_block1 = block.vtx[1].GetHash(); + filter1.insert(hash_in_block1); + CThinBlock thinblock6(block1, filter1); + CXThinBlock xthinblock6(block1, &filter1); + BOOST_CHECK(thinblock6.vMissingTx.size() >= 7 && thinblock6.vMissingTx.size() <= 8); + BOOST_CHECK(xthinblock6.vMissingTx.size() >= 7 && xthinblock6.vMissingTx.size() <= 8); + + /*collision test*/ + BOOST_CHECK(!xthinblock6.collision); + block.vtx.push_back(block1.vtx[1]); // duplicate tx + filter1.clear(); + CXThinBlock xthinblock7(block, &filter1); + BOOST_CHECK(xthinblock7.collision); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/thinblock_util_tests.cpp b/src/test/thinblock_util_tests.cpp new file mode 100644 index 00000000..d75ca2fb --- /dev/null +++ b/src/test/thinblock_util_tests.cpp @@ -0,0 +1,42 @@ +// Copyright (c) 2013-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "thinblock.h" +#include "test/test_bitcoin.h" +#include +#include + + +BOOST_FIXTURE_TEST_SUITE(thinblock_util_tests, BasicTestingSetup) +BOOST_AUTO_TEST_CASE(TestCBufferedFile) +{ + const double pinf = std::numeric_limits::infinity(); + const double ninf = -pinf; + const double qnan = std::numeric_limits::quiet_NaN(); + const double snan = std::numeric_limits::signaling_NaN(); + + // exercise special values as well to make sure they don't due + // any overruns etc. + formatInfoUnit(pinf); + formatInfoUnit(ninf); + formatInfoUnit(qnan); + formatInfoUnit(snan); + + assert(formatInfoUnit(-1001000.0) == "-1.00MB"); + assert(formatInfoUnit(-1001.0) == "-1.00KB"); + assert(formatInfoUnit(-1.0) == "-1.00B"); + assert(formatInfoUnit(0.1) == "0.10B"); + assert(formatInfoUnit(1.0) == "1.00B"); + assert(formatInfoUnit(10.) == "10.00B"); + assert(formatInfoUnit(1e3 + 1e0) == "1.00KB"); + assert(formatInfoUnit(1e6 + 1e2) == "1.00MB"); + assert(formatInfoUnit(1e9 + 1e5) == "1.00GB"); + assert(formatInfoUnit(1e12 + 1e8) == "1.00TB"); + assert(formatInfoUnit(1e15 + 1e11) == "1.00PB"); + assert(formatInfoUnit(1e18 + 1e14) == "1.00EB"); + assert(formatInfoUnit(1e21 + 1e17) == "1000.10EB"); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp new file mode 100644 index 00000000..75dfbd1e --- /dev/null +++ b/src/test/timedata_tests.cpp @@ -0,0 +1,40 @@ +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +#include "timedata.h" +#include "test/test_bitcoin.h" + +#include + +using namespace std; + +BOOST_FIXTURE_TEST_SUITE(timedata_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(util_MedianFilter) +{ + CMedianFilter filter(5, 15); + + BOOST_CHECK_EQUAL(filter.median(), 15); + + filter.input(20); // [15 20] + BOOST_CHECK_EQUAL(filter.median(), 17); + + filter.input(30); // [15 20 30] + BOOST_CHECK_EQUAL(filter.median(), 20); + + filter.input(3); // [3 15 20 30] + BOOST_CHECK_EQUAL(filter.median(), 17); + + filter.input(7); // [3 7 15 20 30] + BOOST_CHECK_EQUAL(filter.median(), 15); + + filter.input(18); // [3 7 18 20 30] + BOOST_CHECK_EQUAL(filter.median(), 18); + + filter.input(0); // [0 3 7 18 30] + BOOST_CHECK_EQUAL(filter.median(), 7); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 6e405c0d..a707c01b 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -1,59 +1,143 @@ +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "data/tx_invalid.json.h" +#include "data/tx_valid.json.h" +#include "test/test_bitcoin.h" + +#include "clientversion.h" +#include "consensus/validation.h" +#include "core_io.h" +#include "key.h" +#include "keystore.h" +#include "main.h" // For CheckTransaction +#include "policy/policy.h" +#include "script/script.h" +#include "script/script_error.h" +#include "utilstrencodings.h" + #include #include + +#include +#include +#include +#include #include -#include "json/json_spirit_writer_template.h" -#include "main.h" -#include "wallet.h" +#include using namespace std; -using namespace json_spirit; // In script_tests.cpp -extern Array read_json(const std::string& filename); -extern CScript ParseScript(string s); +extern UniValue read_json(const std::string &jsondata); + +static std::map mapFlagNames = + boost::assign::map_list_of(string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE)(string("P2SH"), + (unsigned int)SCRIPT_VERIFY_P2SH)(string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC)(string("DERSIG"), + (unsigned int)SCRIPT_VERIFY_DERSIG)(string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S)(string("SIGPUSHONLY"), + (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY)(string("MINIMALDATA"), + (unsigned int)SCRIPT_VERIFY_MINIMALDATA)(string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY)( + string("DISCOURAGE_UPGRADABLE_NOPS"), + (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)(string("CLEANSTACK"), + (unsigned int)SCRIPT_VERIFY_CLEANSTACK)(string("NULLFAIL"), (unsigned int)SCRIPT_VERIFY_NULLFAIL)( + string("CHECKLOCKTIMEVERIFY"), + (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)(string("CHECKSEQUENCEVERIFY"), + (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)(std::string("SIGHASH_FORKID"), + (unsigned int)SCRIPT_ENABLE_SIGHASH_FORKID); + +unsigned int ParseScriptFlags(string strFlags) +{ + if (strFlags.empty()) + { + return 0; + } + unsigned int flags = 0; + vector words; + boost::algorithm::split(words, strFlags, boost::algorithm::is_any_of(",")); -BOOST_AUTO_TEST_SUITE(transaction_tests) + BOOST_FOREACH (string word, words) + { + if (!mapFlagNames.count(word)) + BOOST_ERROR("Bad test: unknown verification flag '" << word << "'"); + flags |= mapFlagNames[word]; + } + + return flags; +} + +string FormatScriptFlags(unsigned int flags) +{ + if (flags == 0) + { + return ""; + } + string ret; + std::map::const_iterator it = mapFlagNames.begin(); + while (it != mapFlagNames.end()) + { + if (flags & it->second) + { + ret += it->first + ","; + } + it++; + } + return ret.substr(0, ret.size() - 1); +} + +BOOST_FIXTURE_TEST_SUITE(transaction_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(tx_valid) { // Read tests from test/data/tx_valid.json // Format is an array of arrays // Inner arrays are either [ "comment" ] - // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, enforceP2SH + // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, verifyFlags // ... where all scripts are stringified scripts. - Array tests = read_json("tx_valid.json"); + // + // verifyFlags is a comma separated list of script verification flags to apply, or "NONE" + UniValue tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid))); - for (auto& tv: tests) + ScriptError err; + for (unsigned int idx = 0; idx < tests.size(); idx++) { - Array test = tv.get_array(); - string strTest = write_string(tv, false); - if (test[0].type() == array_type) + UniValue test = tests[idx]; + string strTest = test.write(); + if (test[0].isArray()) { - if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type) + if (test.size() != 3 || !test[1].isStr() || !test[2].isStr()) { BOOST_ERROR("Bad test: " << strTest); continue; } map mapprevOutScriptPubKeys; - Array inputs = test[0].get_array(); + std::map mapprevOutValues; + UniValue inputs = test[0].get_array(); bool fValid = true; - for (auto& input: inputs) + for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { - if (input.type() != array_type) + const UniValue &input = inputs[inpIdx]; + if (!input.isArray()) { fValid = false; break; } - Array vinput = input.get_array(); + UniValue vinput = input.get_array(); if (vinput.size() != 3) { fValid = false; break; } - mapprevOutScriptPubKeys[COutPoint(uint256(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str()); + COutPoint outpoint(uint256S(vinput[0].get_str()), vinput[1].get_int()); + mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str()); + if (vinput.size() >= 4) + { + mapprevOutValues[outpoint] = vinput[3].get_int64(); + } } if (!fValid) { @@ -66,7 +150,9 @@ BOOST_AUTO_TEST_CASE(tx_valid) CTransaction tx; stream >> tx; - BOOST_CHECK_MESSAGE(tx.CheckTransaction(), strTest); + CValidationState state; + BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest); + BOOST_CHECK(state.IsValid()); for (unsigned int i = 0; i < tx.vin.size(); i++) { @@ -76,7 +162,17 @@ BOOST_AUTO_TEST_CASE(tx_valid) break; } - BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool(), 0), strTest); + CAmount amount = 0; + if (mapprevOutValues.count(tx.vin[i].prevout)) + { + amount = mapprevOutValues[tx.vin[i].prevout]; + } + + unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); + BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], + verify_flags, TransactionSignatureChecker(&tx, i, amount, verify_flags), &err), + strTest); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } } } @@ -87,40 +183,51 @@ BOOST_AUTO_TEST_CASE(tx_invalid) // Read tests from test/data/tx_invalid.json // Format is an array of arrays // Inner arrays are either [ "comment" ] - // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, enforceP2SH + // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, verifyFlags // ... where all scripts are stringified scripts. - Array tests = read_json("tx_invalid.json"); + // + // verifyFlags is a comma separated list of script verification flags to apply, or "NONE" + UniValue tests = + read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid))); - for (auto& tv: tests) + ScriptError err; + for (unsigned int idx = 0; idx < tests.size(); idx++) { - Array test = tv.get_array(); - string strTest = write_string(tv, false); - if (test[0].type() == array_type) + UniValue test = tests[idx]; + string strTest = test.write(); + if (test[0].isArray()) { - if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type) + if (test.size() != 3 || !test[1].isStr() || !test[2].isStr()) { BOOST_ERROR("Bad test: " << strTest); continue; } map mapprevOutScriptPubKeys; - Array inputs = test[0].get_array(); + std::map mapprevOutValues; + UniValue inputs = test[0].get_array(); bool fValid = true; - for (auto& input: inputs) + for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { - if (input.type() != array_type) + const UniValue &input = inputs[inpIdx]; + if (!input.isArray()) { fValid = false; break; } - Array vinput = input.get_array(); + UniValue vinput = input.get_array(); if (vinput.size() != 3) { fValid = false; break; } - mapprevOutScriptPubKeys[COutPoint(uint256(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str()); + COutPoint outpoint(uint256S(vinput[0].get_str()), vinput[1].get_int()); + mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str()); + if (vinput.size() >= 4) + { + mapprevOutValues[outpoint] = vinput[3].get_int64(); + } } if (!fValid) { @@ -133,7 +240,8 @@ BOOST_AUTO_TEST_CASE(tx_invalid) CTransaction tx; stream >> tx; - fValid = tx.CheckTransaction(); + CValidationState state; + fValid = CheckTransaction(tx, state) && state.IsValid(); for (unsigned int i = 0; i < tx.vin.size() && fValid; i++) { @@ -143,10 +251,18 @@ BOOST_AUTO_TEST_CASE(tx_invalid) break; } - fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool(), 0); - } + CAmount amount = 0; + if (mapprevOutValues.count(tx.vin[i].prevout)) + { + amount = mapprevOutValues[tx.vin[i].prevout]; + } + unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); + fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], verify_flags, + TransactionSignatureChecker(&tx, i, amount, verify_flags), &err); + } BOOST_CHECK_MESSAGE(!fValid, strTest); + BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err)); } } } @@ -154,16 +270,33 @@ BOOST_AUTO_TEST_CASE(tx_invalid) BOOST_AUTO_TEST_CASE(basic_transaction_tests) { // Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) - unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; - vector vch(ch, ch + sizeof(ch) -1); + unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, + 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, + 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, + 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, + 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, + 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, + 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, + 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, + 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, + 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, + 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, + 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, + 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, + 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; + vector vch(ch, ch + sizeof(ch) - 1); CDataStream stream(vch, SER_DISK, CLIENT_VERSION); - CTransaction tx; + CMutableTransaction tx; stream >> tx; - BOOST_CHECK_MESSAGE(tx.CheckTransaction(), "Simple deserialized transaction should be valid."); + CValidationState state; + BOOST_CHECK_MESSAGE( + CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid."); // Check that duplicate txins fail tx.vin.push_back(tx.vin[0]); - BOOST_CHECK_MESSAGE(!tx.CheckTransaction(), "Transaction with duplicate txins should be invalid."); + BOOST_CHECK_MESSAGE( + !CheckTransaction(tx, state) || !state.IsValid(), "Transaction with duplicate txins should be invalid."); } // @@ -172,10 +305,9 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests) // paid to a TX_PUBKEY, the second 21 and 22 CENT outputs // paid to a TX_PUBKEYHASH. // -static std::vector -SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet) +static std::vector SetupDummyInputs(CBasicKeyStore &keystoreRet, CCoinsViewCache &coinsRet) { - std::vector dummyTransactions; + std::vector dummyTransactions; dummyTransactions.resize(2); // Add some keys to the keystore: @@ -188,18 +320,18 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet) // Create some dummy input transactions dummyTransactions[0].vout.resize(2); - dummyTransactions[0].vout[0].nValue = 11*CENT; - dummyTransactions[0].vout[0].scriptPubKey << key[0].GetPubKey() << OP_CHECKSIG; - dummyTransactions[0].vout[1].nValue = 50*CENT; - dummyTransactions[0].vout[1].scriptPubKey << key[1].GetPubKey() << OP_CHECKSIG; - inputsRet[dummyTransactions[0].GetHash()] = make_pair(CTxIndex(), dummyTransactions[0]); + dummyTransactions[0].vout[0].nValue = 11 * CENT; + dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; + dummyTransactions[0].vout[1].nValue = 50 * CENT; + dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; + AddCoins(coinsRet, dummyTransactions[0], 0); dummyTransactions[1].vout.resize(2); - dummyTransactions[1].vout[0].nValue = 21*CENT; - dummyTransactions[1].vout[0].scriptPubKey.SetDestination(key[2].GetPubKey().GetID()); - dummyTransactions[1].vout[1].nValue = 22*CENT; - dummyTransactions[1].vout[1].scriptPubKey.SetDestination(key[3].GetPubKey().GetID()); - inputsRet[dummyTransactions[1].GetHash()] = make_pair(CTxIndex(), dummyTransactions[1]); + dummyTransactions[1].vout[0].nValue = 21 * CENT; + dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID()); + dummyTransactions[1].vout[1].nValue = 22 * CENT; + dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID()); + AddCoins(coinsRet, dummyTransactions[1], 0); return dummyTransactions; } @@ -207,10 +339,11 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet) BOOST_AUTO_TEST_CASE(test_Get) { CBasicKeyStore keystore; - MapPrevTx dummyInputs; - std::vector dummyTransactions = SetupDummyInputs(keystore, dummyInputs); + CCoinsView coinsDummy; + CCoinsViewCache coins(&coinsDummy); + std::vector dummyTransactions = SetupDummyInputs(keystore, coins); - CTransaction t1; + CMutableTransaction t1; t1.vin.resize(3); t1.vin[0].prevout.hash = dummyTransactions[0].GetHash(); t1.vin[0].prevout.n = 1; @@ -222,43 +355,118 @@ BOOST_AUTO_TEST_CASE(test_Get) t1.vin[2].prevout.n = 1; t1.vin[2].scriptSig << std::vector(65, 0) << std::vector(33, 4); t1.vout.resize(2); - t1.vout[0].nValue = 90*CENT; + t1.vout[0].nValue = 90 * CENT; t1.vout[0].scriptPubKey << OP_1; - BOOST_CHECK(t1.AreInputsStandard(dummyInputs)); - BOOST_CHECK_EQUAL(t1.GetValueIn(dummyInputs), (50+21+22)*CENT); - - // Adding extra junk to the scriptSig should make it non-standard: - t1.vin[0].scriptSig << OP_11; - BOOST_CHECK(!t1.AreInputsStandard(dummyInputs)); - - // ... as should not having enough: - t1.vin[0].scriptSig = CScript(); - BOOST_CHECK(!t1.AreInputsStandard(dummyInputs)); + BOOST_CHECK(AreInputsStandard(t1, coins)); + BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50 + 21 + 22) * CENT); } -BOOST_AUTO_TEST_CASE(test_GetThrow) + +BOOST_AUTO_TEST_CASE(test_IsStandard) { + LOCK(cs_main); CBasicKeyStore keystore; - MapPrevTx dummyInputs; - std::vector dummyTransactions = SetupDummyInputs(keystore, dummyInputs); - - MapPrevTx missingInputs; - - CTransaction t1; - t1.vin.resize(3); - t1.vin[0].prevout.hash = dummyTransactions[0].GetHash(); - t1.vin[0].prevout.n = 0; - t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();; - t1.vin[1].prevout.n = 0; - t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();; - t1.vin[2].prevout.n = 1; - t1.vout.resize(2); - t1.vout[0].nValue = 90*CENT; - t1.vout[0].scriptPubKey << OP_1; - - BOOST_CHECK_THROW(t1.AreInputsStandard(missingInputs), runtime_error); - BOOST_CHECK_THROW(t1.GetValueIn(missingInputs), runtime_error); + CCoinsView coinsDummy; + CCoinsViewCache coins(&coinsDummy); + std::vector dummyTransactions = SetupDummyInputs(keystore, coins); + + CMutableTransaction t; + t.vin.resize(1); + t.vin[0].prevout.hash = dummyTransactions[0].GetHash(); + t.vin[0].prevout.n = 1; + t.vin[0].scriptSig << std::vector(65, 0); + t.vout.resize(1); + t.vout[0].nValue = 90 * CENT; + CKey key; + key.MakeNewKey(true); + t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + + string reason; + BOOST_CHECK(IsStandardTx(t, reason)); + + // Check dust with default relay fee: + minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); + CAmount nDustThreshold = 182 * minRelayTxFee.GetFeePerK() / 1000 * 3; + BOOST_CHECK_EQUAL(nDustThreshold, 546); + // dust: + t.vout[0].nValue = nDustThreshold - 1; + BOOST_CHECK(!IsStandardTx(t, reason)); + // not dust: + t.vout[0].nValue = nDustThreshold; + BOOST_CHECK(IsStandardTx(t, reason)); + + // Check dust with odd relay fee to verify rounding: + // nDustThreshold = 182 * 1234 / 1000 * 3 + minRelayTxFee = CFeeRate(1234); + // dust: + t.vout[0].nValue = 672 - 1; + BOOST_CHECK(!IsStandardTx(t, reason)); + // not dust: + t.vout[0].nValue = 672; + BOOST_CHECK(IsStandardTx(t, reason)); + minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); + + t.vout[0].scriptPubKey = CScript() << OP_1; + BOOST_CHECK(!IsStandardTx(t, reason)); + + // MAX_OP_RETURN_RELAY-byte TX_NULL_DATA (standard) + t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962" + "e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a671" + "30b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size()); + BOOST_CHECK(IsStandardTx(t, reason)); + + // MAX_OP_RETURN_RELAY+1-byte TX_NULL_DATA (non-standard) + t.vout[0].scriptPubKey = + CScript() << OP_RETURN + << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afd" + "b0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"); + BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size()); + BOOST_CHECK(!IsStandardTx(t, reason)); + + // Data payload can be encoded in any way... + t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex(""); + BOOST_CHECK(IsStandardTx(t, reason)); + t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("00") << ParseHex("01"); + BOOST_CHECK(IsStandardTx(t, reason)); + // OP_RESERVED *is* considered to be a PUSHDATA type opcode by IsPushOnly()! + t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RESERVED << -1 << 0 << ParseHex("01") << 2 << 3 << 4 << 5 << 6 + << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16; + BOOST_CHECK(IsStandardTx(t, reason)); + t.vout[0].scriptPubKey = + CScript() << OP_RETURN << 0 << ParseHex("01") << 2 + << ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + BOOST_CHECK(IsStandardTx(t, reason)); + + // ...so long as it only contains PUSHDATA's + t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RETURN; + BOOST_CHECK(!IsStandardTx(t, reason)); + + // TX_NULL_DATA w/o PUSHDATA + t.vout.resize(1); + t.vout[0].scriptPubKey = CScript() << OP_RETURN; + BOOST_CHECK(IsStandardTx(t, reason)); + + // Only one TX_NULL_DATA permitted in all cases + t.vout.resize(2); + t.vout[0].scriptPubKey = + CScript() << OP_RETURN + << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + t.vout[1].scriptPubKey = + CScript() << OP_RETURN + << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + BOOST_CHECK(!IsStandardTx(t, reason)); + + t.vout[0].scriptPubKey = + CScript() << OP_RETURN + << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + t.vout[1].scriptPubKey = CScript() << OP_RETURN; + BOOST_CHECK(!IsStandardTx(t, reason)); + + t.vout[0].scriptPubKey = CScript() << OP_RETURN; + t.vout[1].scriptPubKey = CScript() << OP_RETURN; + BOOST_CHECK(!IsStandardTx(t, reason)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp new file mode 100644 index 00000000..389af927 --- /dev/null +++ b/src/test/txvalidationcache_tests.cpp @@ -0,0 +1,306 @@ +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "consensus/validation.h" +#include "key.h" +#include "main.h" +#include "miner.h" +#include "parallel.h" +#include "pubkey.h" +#include "random.h" +#include "script/standard.h" +#include "test/test_bitcoin.h" +#include "txmempool.h" +#include "utiltime.h" + +#include + +extern bool AddOrphanTx(const CTransaction &tx, NodeId peer); +extern void EraseOrphansByTime(); +extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans, uint64_t nMaxBytes); +extern void LimitMempoolSize(CTxMemPool &pool, size_t limit, unsigned long age); + +BOOST_AUTO_TEST_SUITE(txvalidationcache_tests) // BU harmonize suite name with filename + +static bool ToMemPool(CMutableTransaction &tx) +{ + LOCK(cs_main); + + CValidationState state; + bool fMissingInputs = false; + return AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, true, false); +} + +BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) +{ + // Make sure skipping validation of transctions that were + // validated going into the memory pool does not allow + // double-spends in blocks to pass validation when they should not. + + CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; + + + unsigned int sighashType = SIGHASH_ALL; + if (chainActive.Tip()->IsforkActiveOnNextBlock(miningForkTime.value)) + sighashType |= SIGHASH_FORKID; + + // Create a double-spend of mature coinbase txn: + std::vector spends; + spends.resize(2); + for (int i = 0; i < 2; i++) + { + spends[i].vin.resize(1); + spends[i].vin[0].prevout.hash = coinbaseTxns[0].GetHash(); + spends[i].vin[0].prevout.n = 0; + spends[i].vout.resize(1); + spends[i].vout[0].nValue = 11 * CENT; + spends[i].vout[0].scriptPubKey = scriptPubKey; + + // Sign: + std::vector vchSig; + uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, sighashType, coinbaseTxns[0].vout[0].nValue, 0); + BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); + vchSig.push_back((unsigned char)sighashType); + spends[i].vin[0].scriptSig << vchSig; + } + + CBlock block; + + // Test 1: block with both of those transactions should be rejected. + block = CreateAndProcessBlock(spends, scriptPubKey); + BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); + + // Test 2: ... and should be rejected if spend1 is in the memory pool + BOOST_CHECK(ToMemPool(spends[0])); + block = CreateAndProcessBlock(spends, scriptPubKey); + BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); + mempool.clear(); + + // Test 3: ... and should be rejected if spend2 is in the memory pool + BOOST_CHECK(ToMemPool(spends[1])); + block = CreateAndProcessBlock(spends, scriptPubKey); + BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); + mempool.clear(); + + // Final sanity test: first spend in mempool, second in block, that's OK: + std::vector oneSpend; + oneSpend.push_back(spends[0]); + BOOST_CHECK(ToMemPool(spends[1])); + block = CreateAndProcessBlock(oneSpend, scriptPubKey); + BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); + // spends[1] should have been removed from the mempool when the + // block with spends[0] is accepted: + BOOST_CHECK_EQUAL(mempool.size(), 0); + mempool.clear(); +} + +BOOST_FIXTURE_TEST_CASE(uncache_coins, TestChain100Setup) +{ + int64_t nStartTime = GetTime(); + nLastOrphanCheck = nStartTime; + SetMockTime(nStartTime); // Overrides future calls to GetTime() + + mempool.clear(); + pcoinsTip->Flush(); + + // Make sure coins are uncached when txns are not accepted into the memory pool + // and also verify they are uncached when orphans or txns are evicted from either the + // orphan cache or the transaction memory pool. + CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; + + unsigned int sighashType = SIGHASH_ALL; + if (chainActive.Tip()->IsforkActiveOnNextBlock(miningForkTime.value)) + sighashType |= SIGHASH_FORKID; + + std::vector spends; + + // Add valid txns to the memory pool. The coins should be present in the coins cache. + spends.resize(1); + spends[0].vin.resize(1); + spends[0].vin[0].prevout.hash = coinbaseTxns[0].GetHash(); + spends[0].vin[0].prevout.n = 0; + spends[0].vout.resize(1); + spends[0].vout[0].nValue = 11 * CENT; + spends[0].vout[0].scriptPubKey = scriptPubKey; + + // Sign: + std::vector vchSig1; + uint256 hash1 = SignatureHash(scriptPubKey, spends[0], 0, sighashType, coinbaseTxns[0].vout[0].nValue, 0); + BOOST_CHECK(coinbaseKey.Sign(hash1, vchSig1)); + vchSig1.push_back((unsigned char)sighashType); + spends[0].vin[0].scriptSig << vchSig1; + + BOOST_CHECK(ToMemPool(spends[0])); + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[0].vin[0].prevout)); + + // Try to add the same tx to the memory pool. The coins should still be present. + BOOST_CHECK(!ToMemPool(spends[0])); + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[0].vin[0].prevout)); + + // Try to add an invalid txn to the memory pool. The coins for the previous txn should + // still be present and but the coins from the rejected txn should not be present. + spends.resize(2); + spends[1].vin.resize(1); + spends[1].vin[0].prevout.hash = coinbaseTxns[1].GetHash(); + spends[1].vin[0].prevout.n = 0; + spends[1].vout.resize(1); + spends[1].vout[0].nValue = 11 * CENT; + spends[1].vout[0].scriptPubKey = scriptPubKey; + + // Sign: + std::vector vchSig2; + uint256 hash2 = SignatureHash(scriptPubKey, spends[1], 0, sighashType, coinbaseTxns[1].vout[0].nValue, 0); + BOOST_CHECK(coinbaseKey.Sign(hash2, vchSig2)); + vchSig2.push_back((unsigned char)sighashType); + spends[1].vin[0].scriptSig << vchSig2; + + BOOST_CHECK(!ToMemPool(spends[1])); + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[0].vin[0].prevout)); // not uncached because from a previous txn + BOOST_CHECK(!pcoinsTip->HaveCoinInCache(spends[1].vin[0].prevout)); + + // Add an orphan to the orphan cache. The valid inputs should be present in the coins cache. + spends.resize(3); + spends[2].vin.resize(3); + spends[2].vin[0].prevout.hash = GetRandHash(); + spends[2].vin[0].prevout.n = 0; + spends[2].vin[1].prevout.hash = GetRandHash(); + spends[2].vin[1].prevout.n = 0; + spends[2].vin[2].prevout.hash = coinbaseTxns[2].GetHash(); + spends[2].vin[2].prevout.n = 0; + spends[2].vout.resize(1); + spends[2].vout[0].nValue = 799999999; + spends[2].vout[0].scriptPubKey = scriptPubKey; + + // Sign: + std::vector vchSig3; + uint256 hash3 = SignatureHash(scriptPubKey, spends[2], 0, sighashType, coinbaseTxns[2].vout[0].nValue, 0); + BOOST_CHECK(coinbaseKey.Sign(hash3, vchSig3)); + vchSig3.push_back((unsigned char)sighashType); + spends[2].vin[0].scriptSig << vchSig2; + + BOOST_CHECK(!ToMemPool(spends[2])); + { + LOCK(cs_orphancache); + BOOST_CHECK(AddOrphanTx(spends[2], 1)); + } + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[0].vin[0].prevout)); // valid coin from previous txn + BOOST_CHECK(!pcoinsTip->HaveCoinInCache(spends[2].vin[0].prevout)); + BOOST_CHECK(!pcoinsTip->HaveCoinInCache(spends[2].vin[1].prevout)); + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[2].vin[2].prevout)); // the only valid coin from the orphantx + + // Remove valid orphans by time. The coins should be removed from the coins cache + { + LOCK(cs_orphancache); + SetMockTime(nStartTime + 3600 * DEFAULT_ORPHANPOOL_EXPIRY + 300); + EraseOrphansByTime(); + } + + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[0].vin[0].prevout)); // valid coin from previous txn + BOOST_CHECK(!pcoinsTip->HaveCoinInCache(spends[2].vin[2].prevout)); // the valid coin from orphantx is uncached + + // Remove valid orphans by size. The coins should be removed from the coins cache + BOOST_CHECK(!ToMemPool(spends[2])); + { + LOCK(cs_orphancache); + BOOST_CHECK(AddOrphanTx(spends[2], 1)); + } + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[0].vin[0].prevout)); // valid coin from previous txn + BOOST_CHECK(!pcoinsTip->HaveCoinInCache(spends[2].vin[0].prevout)); + BOOST_CHECK(!pcoinsTip->HaveCoinInCache(spends[2].vin[1].prevout)); + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[2].vin[2].prevout)); // the only valid coin from the orphantx + + { + LOCK(cs_orphancache); + LimitOrphanTxSize(0, 0); + } + + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[0].vin[0].prevout)); // valid coin from previous txn + BOOST_CHECK(!pcoinsTip->HaveCoinInCache(spends[2].vin[2].prevout)); // the valid coin from orphantx is uncached + + // Evict the valid previous tx, by time. The coins should be removed from the coins cache + SetMockTime(nStartTime + 1 + 72 * 60 * 60); // move to 1 second beyond time to evict + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[0].vin[0].prevout)); // valid coin from previous txn + LimitMempoolSize(mempool, 100 * 1000 * 1000, 72 * 60 * 60); + BOOST_CHECK(!pcoinsTip->HaveCoinInCache(spends[0].vin[0].prevout)); // valid coin from previous txn + + // Add a tx to the memory pool. The valid inputs should be present in the coins cache. + spends.resize(4); + spends[3].vin.resize(1); + spends[3].vin[0].prevout.hash = coinbaseTxns[0].GetHash(); + spends[3].vin[0].prevout.n = 0; + spends[3].vout.resize(1); + spends[3].vout[0].nValue = 11 * CENT; + spends[3].vout[0].scriptPubKey = scriptPubKey; + + // Sign: + std::vector vchSig4; + uint256 hash4 = SignatureHash(scriptPubKey, spends[3], 0, sighashType, coinbaseTxns[3].vout[0].nValue, 0); + BOOST_CHECK(coinbaseKey.Sign(hash4, vchSig4)); + vchSig4.push_back((unsigned char)sighashType); + spends[3].vin[0].scriptSig << vchSig4; + + BOOST_CHECK(ToMemPool(spends[3])); + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[3].vin[0].prevout)); + + // Evict a valid tx by size of memory pool. The coins should be removed from the coins cache + SetMockTime(nStartTime + 1); // change start time so we are well within the limits + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[3].vin[0].prevout)); // valid coin from previous txn + LimitMempoolSize(mempool, 0, 72 * 60 * 60); // limit mempool size to zero + BOOST_CHECK(!pcoinsTip->HaveCoinInCache(spends[3].vin[0].prevout)); // valid coin from previous txn + + /** Simulate the following scenario: + * Add an orphan to the orphan pool + * then add the parent to the mempool which causes the orphan to also be pulled into the mempool. + * then delete the orphan using EraseOrphanTx(hash). + * Result: All coins should still be present in cache. + */ + + // Add an orphan to the orphan cache. The valid inputs should be present in the coins cache. + spends.resize(5); + spends[4].vin.resize(3); + spends[4].vin[0].prevout.hash = GetRandHash(); + spends[4].vin[0].prevout.n = 0; + spends[4].vin[1].prevout.hash = GetRandHash(); + spends[4].vin[1].prevout.n = 0; + spends[4].vin[2].prevout.hash = coinbaseTxns[5].GetHash(); + spends[4].vin[2].prevout.n = 0; + spends[4].vout.resize(1); + spends[4].vout[0].nValue = 799999999; + spends[4].vout[0].scriptPubKey = scriptPubKey; + + // Sign: + std::vector vchSig5; + uint256 hash5 = SignatureHash(scriptPubKey, spends[2], 0, sighashType, coinbaseTxns[5].vout[0].nValue, 0); + BOOST_CHECK(coinbaseKey.Sign(hash5, vchSig5)); + vchSig5.push_back((unsigned char)sighashType); + spends[4].vin[0].scriptSig << vchSig5; + + BOOST_CHECK(!ToMemPool(spends[4])); + { + LOCK(cs_orphancache); + BOOST_CHECK(AddOrphanTx(spends[4], 1)); + } + BOOST_CHECK(!pcoinsTip->HaveCoinInCache(spends[4].vin[0].prevout)); + BOOST_CHECK(!pcoinsTip->HaveCoinInCache(spends[4].vin[1].prevout)); + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[4].vin[2].prevout)); // the only valid coin from the orphantx + + // All we need to do to simluate the above scenario is now erase the orphan tx from the orphan cache as it + // would be if the orphan was moved into the mempool. + // Result: All the coins should still be remaining in the coins cache. + { + LOCK(cs_orphancache); + EraseOrphanTx(spends[4].GetHash()); + } + BOOST_CHECK(pcoinsTip->HaveCoinInCache(spends[4].vin[2].prevout)); + + + // cleanup + mempool.clear(); + mapOrphanTransactions.clear(); + pcoinsTip->Flush(); + SetMockTime(0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index efdc8a6a..9042a9d9 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -1,18 +1,271 @@ +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "uint256.h" +#include "arith_uint256.h" +#include "test/test_bitcoin.h" +#include "version.h" + #include +#include +#include +#include +#include +#include +#include +#include -#include "uint256.h" +BOOST_FIXTURE_TEST_SUITE(uint256_tests, BasicTestingSetup) + +const unsigned char R1Array[] = "\x9c\x52\x4a\xdb\xcf\x56\x11\x12\x2b\x29\x12\x5e\x5d\x35\xd2\xd2" + "\x22\x81\xaa\xb5\x33\xf0\x08\x32\xd5\x56\xb1\xf9\xea\xe5\x1d\x7d"; +const char R1ArrayHex[] = "7D1DE5EAF9B156D53208F033B5AA8122D2d2355d5e12292b121156cfdb4a529c"; +const uint256 R1L = uint256(std::vector(R1Array, R1Array + 32)); +const uint160 R1S = uint160(std::vector(R1Array, R1Array + 20)); + +const unsigned char R2Array[] = "\x70\x32\x1d\x7c\x47\xa5\x6b\x40\x26\x7e\x0a\xc3\xa6\x9c\xb6\xbf" + "\x13\x30\x47\xa3\x19\x2d\xda\x71\x49\x13\x72\xf0\xb4\xca\x81\xd7"; +const uint256 R2L = uint256(std::vector(R2Array, R2Array + 32)); +const uint160 R2S = uint160(std::vector(R2Array, R2Array + 20)); + +const unsigned char ZeroArray[] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; +const uint256 ZeroL = uint256(std::vector(ZeroArray, ZeroArray + 32)); +const uint160 ZeroS = uint160(std::vector(ZeroArray, ZeroArray + 20)); + +const unsigned char OneArray[] = "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; +const uint256 OneL = uint256(std::vector(OneArray, OneArray + 32)); +const uint160 OneS = uint160(std::vector(OneArray, OneArray + 20)); + +const unsigned char MaxArray[] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; +const uint256 MaxL = uint256(std::vector(MaxArray, MaxArray + 32)); +const uint160 MaxS = uint160(std::vector(MaxArray, MaxArray + 20)); + +std::string ArrayToString(const unsigned char A[], unsigned int width) +{ + std::stringstream Stream; + Stream << std::hex; + for (unsigned int i = 0; i < width; ++i) + { + Stream << std::setw(2) << std::setfill('0') << (unsigned int)A[width - i - 1]; + } + return Stream.str(); +} + +inline uint160 uint160S(const char *str) +{ + uint160 rv; + rv.SetHex(str); + return rv; +} +inline uint160 uint160S(const std::string &str) +{ + uint160 rv; + rv.SetHex(str); + return rv; +} + +BOOST_AUTO_TEST_CASE(basics) // constructors, equality, inequality +{ + BOOST_CHECK(1 == 0 + 1); + // constructor uint256(vector): + BOOST_CHECK(R1L.ToString() == ArrayToString(R1Array, 32)); + BOOST_CHECK(R1S.ToString() == ArrayToString(R1Array, 20)); + BOOST_CHECK(R2L.ToString() == ArrayToString(R2Array, 32)); + BOOST_CHECK(R2S.ToString() == ArrayToString(R2Array, 20)); + BOOST_CHECK(ZeroL.ToString() == ArrayToString(ZeroArray, 32)); + BOOST_CHECK(ZeroS.ToString() == ArrayToString(ZeroArray, 20)); + BOOST_CHECK(OneL.ToString() == ArrayToString(OneArray, 32)); + BOOST_CHECK(OneS.ToString() == ArrayToString(OneArray, 20)); + BOOST_CHECK(MaxL.ToString() == ArrayToString(MaxArray, 32)); + BOOST_CHECK(MaxS.ToString() == ArrayToString(MaxArray, 20)); + BOOST_CHECK(OneL.ToString() != ArrayToString(ZeroArray, 32)); + BOOST_CHECK(OneS.ToString() != ArrayToString(ZeroArray, 20)); + + // == and != + BOOST_CHECK(R1L != R2L && R1S != R2S); + BOOST_CHECK(ZeroL != OneL && ZeroS != OneS); + BOOST_CHECK(OneL != ZeroL && OneS != ZeroS); + BOOST_CHECK(MaxL != ZeroL && MaxS != ZeroS); + + // String Constructor and Copy Constructor + BOOST_CHECK(uint256S("0x" + R1L.ToString()) == R1L); + BOOST_CHECK(uint256S("0x" + R2L.ToString()) == R2L); + BOOST_CHECK(uint256S("0x" + ZeroL.ToString()) == ZeroL); + BOOST_CHECK(uint256S("0x" + OneL.ToString()) == OneL); + BOOST_CHECK(uint256S("0x" + MaxL.ToString()) == MaxL); + BOOST_CHECK(uint256S(R1L.ToString()) == R1L); + BOOST_CHECK(uint256S(" 0x" + R1L.ToString() + " ") == R1L); + BOOST_CHECK(uint256S("") == ZeroL); + BOOST_CHECK(R1L == uint256S(R1ArrayHex)); + BOOST_CHECK(uint256(R1L) == R1L); + BOOST_CHECK(uint256(ZeroL) == ZeroL); + BOOST_CHECK(uint256(OneL) == OneL); -BOOST_AUTO_TEST_SUITE(uint256_tests) + BOOST_CHECK(uint160S("0x" + R1S.ToString()) == R1S); + BOOST_CHECK(uint160S("0x" + R2S.ToString()) == R2S); + BOOST_CHECK(uint160S("0x" + ZeroS.ToString()) == ZeroS); + BOOST_CHECK(uint160S("0x" + OneS.ToString()) == OneS); + BOOST_CHECK(uint160S("0x" + MaxS.ToString()) == MaxS); + BOOST_CHECK(uint160S(R1S.ToString()) == R1S); + BOOST_CHECK(uint160S(" 0x" + R1S.ToString() + " ") == R1S); + BOOST_CHECK(uint160S("") == ZeroS); + BOOST_CHECK(R1S == uint160S(R1ArrayHex)); + + BOOST_CHECK(uint160(R1S) == R1S); + BOOST_CHECK(uint160(ZeroS) == ZeroS); + BOOST_CHECK(uint160(OneS) == OneS); +} -BOOST_AUTO_TEST_CASE(uint256_equality) +BOOST_AUTO_TEST_CASE(comparison) // <= >= < > { - uint256 num1 = 10; - uint256 num2 = 11; - BOOST_CHECK(num1+1 == num2); + uint256 LastL; + for (int i = 255; i >= 0; --i) + { + uint256 TmpL; + *(TmpL.begin() + (i >> 3)) |= 1 << (7 - (i & 7)); + BOOST_CHECK(LastL < TmpL); + LastL = TmpL; + } - uint64 num3 = 10; - BOOST_CHECK(num1 == num3); - BOOST_CHECK(num1+num2 == num3+num2); + BOOST_CHECK(ZeroL < R1L); + BOOST_CHECK(R2L < R1L); + BOOST_CHECK(ZeroL < OneL); + BOOST_CHECK(OneL < MaxL); + BOOST_CHECK(R1L < MaxL); + BOOST_CHECK(R2L < MaxL); + + uint160 LastS; + for (int i = 159; i >= 0; --i) + { + uint160 TmpS; + *(TmpS.begin() + (i >> 3)) |= 1 << (7 - (i & 7)); + BOOST_CHECK(LastS < TmpS); + LastS = TmpS; + } + BOOST_CHECK(ZeroS < R1S); + BOOST_CHECK(R2S < R1S); + BOOST_CHECK(ZeroS < OneS); + BOOST_CHECK(OneS < MaxS); + BOOST_CHECK(R1S < MaxS); + BOOST_CHECK(R2S < MaxS); +} + +BOOST_AUTO_TEST_CASE(methods) // GetHex SetHex begin() end() size() GetLow64 GetSerializeSize, Serialize, Unserialize +{ + BOOST_CHECK(R1L.GetHex() == R1L.ToString()); + BOOST_CHECK(R2L.GetHex() == R2L.ToString()); + BOOST_CHECK(OneL.GetHex() == OneL.ToString()); + BOOST_CHECK(MaxL.GetHex() == MaxL.ToString()); + uint256 TmpL(R1L); + BOOST_CHECK(TmpL == R1L); + TmpL.SetHex(R2L.ToString()); + BOOST_CHECK(TmpL == R2L); + TmpL.SetHex(ZeroL.ToString()); + BOOST_CHECK(TmpL == uint256()); + + TmpL.SetHex(R1L.ToString()); + BOOST_CHECK(memcmp(R1L.begin(), R1Array, 32) == 0); + BOOST_CHECK(memcmp(TmpL.begin(), R1Array, 32) == 0); + BOOST_CHECK(memcmp(R2L.begin(), R2Array, 32) == 0); + BOOST_CHECK(memcmp(ZeroL.begin(), ZeroArray, 32) == 0); + BOOST_CHECK(memcmp(OneL.begin(), OneArray, 32) == 0); + BOOST_CHECK(R1L.size() == sizeof(R1L)); + BOOST_CHECK(sizeof(R1L) == 32); + BOOST_CHECK(R1L.size() == 32); + BOOST_CHECK(R2L.size() == 32); + BOOST_CHECK(ZeroL.size() == 32); + BOOST_CHECK(MaxL.size() == 32); + BOOST_CHECK(R1L.begin() + 32 == R1L.end()); + BOOST_CHECK(R2L.begin() + 32 == R2L.end()); + BOOST_CHECK(OneL.begin() + 32 == OneL.end()); + BOOST_CHECK(MaxL.begin() + 32 == MaxL.end()); + BOOST_CHECK(TmpL.begin() + 32 == TmpL.end()); + BOOST_CHECK(GetSerializeSize(R1L, 0, PROTOCOL_VERSION) == 32); + BOOST_CHECK(GetSerializeSize(ZeroL, 0, PROTOCOL_VERSION) == 32); + + CDataStream ss(0, PROTOCOL_VERSION); + ss << R1L; + BOOST_CHECK(ss.str() == std::string(R1Array, R1Array + 32)); + ss >> TmpL; + BOOST_CHECK(R1L == TmpL); + ss.clear(); + ss << ZeroL; + BOOST_CHECK(ss.str() == std::string(ZeroArray, ZeroArray + 32)); + ss >> TmpL; + BOOST_CHECK(ZeroL == TmpL); + ss.clear(); + ss << MaxL; + BOOST_CHECK(ss.str() == std::string(MaxArray, MaxArray + 32)); + ss >> TmpL; + BOOST_CHECK(MaxL == TmpL); + ss.clear(); + + BOOST_CHECK(R1S.GetHex() == R1S.ToString()); + BOOST_CHECK(R2S.GetHex() == R2S.ToString()); + BOOST_CHECK(OneS.GetHex() == OneS.ToString()); + BOOST_CHECK(MaxS.GetHex() == MaxS.ToString()); + uint160 TmpS(R1S); + BOOST_CHECK(TmpS == R1S); + TmpS.SetHex(R2S.ToString()); + BOOST_CHECK(TmpS == R2S); + TmpS.SetHex(ZeroS.ToString()); + BOOST_CHECK(TmpS == uint160()); + + TmpS.SetHex(R1S.ToString()); + BOOST_CHECK(memcmp(R1S.begin(), R1Array, 20) == 0); + BOOST_CHECK(memcmp(TmpS.begin(), R1Array, 20) == 0); + BOOST_CHECK(memcmp(R2S.begin(), R2Array, 20) == 0); + BOOST_CHECK(memcmp(ZeroS.begin(), ZeroArray, 20) == 0); + BOOST_CHECK(memcmp(OneS.begin(), OneArray, 20) == 0); + BOOST_CHECK(R1S.size() == sizeof(R1S)); + BOOST_CHECK(sizeof(R1S) == 20); + BOOST_CHECK(R1S.size() == 20); + BOOST_CHECK(R2S.size() == 20); + BOOST_CHECK(ZeroS.size() == 20); + BOOST_CHECK(MaxS.size() == 20); + BOOST_CHECK(R1S.begin() + 20 == R1S.end()); + BOOST_CHECK(R2S.begin() + 20 == R2S.end()); + BOOST_CHECK(OneS.begin() + 20 == OneS.end()); + BOOST_CHECK(MaxS.begin() + 20 == MaxS.end()); + BOOST_CHECK(TmpS.begin() + 20 == TmpS.end()); + BOOST_CHECK(GetSerializeSize(R1S, 0, PROTOCOL_VERSION) == 20); + BOOST_CHECK(GetSerializeSize(ZeroS, 0, PROTOCOL_VERSION) == 20); + + ss << R1S; + BOOST_CHECK(ss.str() == std::string(R1Array, R1Array + 20)); + ss >> TmpS; + BOOST_CHECK(R1S == TmpS); + ss.clear(); + ss << ZeroS; + BOOST_CHECK(ss.str() == std::string(ZeroArray, ZeroArray + 20)); + ss >> TmpS; + BOOST_CHECK(ZeroS == TmpS); + ss.clear(); + ss << MaxS; + BOOST_CHECK(ss.str() == std::string(MaxArray, MaxArray + 20)); + ss >> TmpS; + BOOST_CHECK(MaxS == TmpS); + ss.clear(); +} + +BOOST_AUTO_TEST_CASE(conversion) +{ + BOOST_CHECK(ArithToUint256(UintToArith256(ZeroL)) == ZeroL); + BOOST_CHECK(ArithToUint256(UintToArith256(OneL)) == OneL); + BOOST_CHECK(ArithToUint256(UintToArith256(R1L)) == R1L); + BOOST_CHECK(ArithToUint256(UintToArith256(R2L)) == R2L); + BOOST_CHECK(UintToArith256(ZeroL) == 0); + BOOST_CHECK(UintToArith256(OneL) == 1); + BOOST_CHECK(ArithToUint256(0) == ZeroL); + BOOST_CHECK(ArithToUint256(1) == OneL); + BOOST_CHECK(arith_uint256(R1L.GetHex()) == UintToArith256(R1L)); + BOOST_CHECK(arith_uint256(R2L.GetHex()) == UintToArith256(R2L)); + BOOST_CHECK(R1L.GetHex() == UintToArith256(R1L).GetHex()); + BOOST_CHECK(R2L.GetHex() == UintToArith256(R2L).GetHex()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp new file mode 100644 index 00000000..66bf2adc --- /dev/null +++ b/src/test/univalue_tests.cpp @@ -0,0 +1,334 @@ +// Copyright 2014 BitPay, Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "test/test_bitcoin.h" +#include +#include +#include +#include +#include + +#include + +using namespace std; + +BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(univalue_constructor) +{ + UniValue v1; + BOOST_CHECK(v1.isNull()); + + UniValue v2(UniValue::VSTR); + BOOST_CHECK(v2.isStr()); + + UniValue v3(UniValue::VSTR, "foo"); + BOOST_CHECK(v3.isStr()); + BOOST_CHECK_EQUAL(v3.getValStr(), "foo"); + + UniValue numTest; + BOOST_CHECK(numTest.setNumStr("82")); + BOOST_CHECK(numTest.isNum()); + BOOST_CHECK_EQUAL(numTest.getValStr(), "82"); + + uint64_t vu64 = 82; + UniValue v4(vu64); + BOOST_CHECK(v4.isNum()); + BOOST_CHECK_EQUAL(v4.getValStr(), "82"); + + int64_t vi64 = -82; + UniValue v5(vi64); + BOOST_CHECK(v5.isNum()); + BOOST_CHECK_EQUAL(v5.getValStr(), "-82"); + + int vi = -688; + UniValue v6(vi); + BOOST_CHECK(v6.isNum()); + BOOST_CHECK_EQUAL(v6.getValStr(), "-688"); + + double vd = -7.21; + UniValue v7(vd); + BOOST_CHECK(v7.isNum()); + BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21"); + + string vs("yawn"); + UniValue v8(vs); + BOOST_CHECK(v8.isStr()); + BOOST_CHECK_EQUAL(v8.getValStr(), "yawn"); + + const char *vcs = "zappa"; + UniValue v9(vcs); + BOOST_CHECK(v9.isStr()); + BOOST_CHECK_EQUAL(v9.getValStr(), "zappa"); +} + +BOOST_AUTO_TEST_CASE(univalue_typecheck) +{ + UniValue v1; + BOOST_CHECK(v1.setNumStr("1")); + BOOST_CHECK(v1.isNum()); + BOOST_CHECK_THROW(v1.get_bool(), runtime_error); + + UniValue v2; + BOOST_CHECK(v2.setBool(true)); + BOOST_CHECK_EQUAL(v2.get_bool(), true); + BOOST_CHECK_THROW(v2.get_int(), runtime_error); + + UniValue v3; + BOOST_CHECK(v3.setNumStr("32482348723847471234")); + BOOST_CHECK_THROW(v3.get_int64(), runtime_error); + BOOST_CHECK(v3.setNumStr("1000")); + BOOST_CHECK_EQUAL(v3.get_int64(), 1000); + + UniValue v4; + BOOST_CHECK(v4.setNumStr("2147483648")); + BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648); + BOOST_CHECK_THROW(v4.get_int(), runtime_error); + BOOST_CHECK(v4.setNumStr("1000")); + BOOST_CHECK_EQUAL(v4.get_int(), 1000); + BOOST_CHECK_THROW(v4.get_str(), runtime_error); + BOOST_CHECK_EQUAL(v4.get_real(), 1000); + BOOST_CHECK_THROW(v4.get_array(), runtime_error); + BOOST_CHECK_THROW(v4.getKeys(), runtime_error); + BOOST_CHECK_THROW(v4.getValues(), runtime_error); + BOOST_CHECK_THROW(v4.get_obj(), runtime_error); + + UniValue v5; + BOOST_CHECK(v5.read("[true, 10]")); + BOOST_CHECK_NO_THROW(v5.get_array()); + std::vector vals = v5.getValues(); + BOOST_CHECK_THROW(vals[0].get_int(), runtime_error); + BOOST_CHECK_EQUAL(vals[0].get_bool(), true); + + BOOST_CHECK_EQUAL(vals[1].get_int(), 10); + BOOST_CHECK_THROW(vals[1].get_bool(), runtime_error); +} + +BOOST_AUTO_TEST_CASE(univalue_set) +{ + UniValue v(UniValue::VSTR, "foo"); + v.clear(); + BOOST_CHECK(v.isNull()); + BOOST_CHECK_EQUAL(v.getValStr(), ""); + + BOOST_CHECK(v.setObject()); + BOOST_CHECK(v.isObject()); + BOOST_CHECK_EQUAL(v.size(), 0); + BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ); + BOOST_CHECK(v.empty()); + + BOOST_CHECK(v.setArray()); + BOOST_CHECK(v.isArray()); + BOOST_CHECK_EQUAL(v.size(), 0); + + BOOST_CHECK(v.setStr("zum")); + BOOST_CHECK(v.isStr()); + BOOST_CHECK_EQUAL(v.getValStr(), "zum"); + + BOOST_CHECK(v.setFloat(-1.01)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-1.01"); + + BOOST_CHECK(v.setInt((int)1023)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "1023"); + + BOOST_CHECK(v.setInt((int64_t)-1023LL)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-1023"); + + BOOST_CHECK(v.setInt((uint64_t)1023ULL)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "1023"); + + BOOST_CHECK(v.setNumStr("-688")); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-688"); + + BOOST_CHECK(v.setBool(false)); + BOOST_CHECK_EQUAL(v.isBool(), true); + BOOST_CHECK_EQUAL(v.isTrue(), false); + BOOST_CHECK_EQUAL(v.isFalse(), true); + BOOST_CHECK_EQUAL(v.getBool(), false); + + BOOST_CHECK(v.setBool(true)); + BOOST_CHECK_EQUAL(v.isBool(), true); + BOOST_CHECK_EQUAL(v.isTrue(), true); + BOOST_CHECK_EQUAL(v.isFalse(), false); + BOOST_CHECK_EQUAL(v.getBool(), true); + + BOOST_CHECK(!v.setNumStr("zombocom")); + + BOOST_CHECK(v.setNull()); + BOOST_CHECK(v.isNull()); +} + +BOOST_AUTO_TEST_CASE(univalue_array) +{ + UniValue arr(UniValue::VARR); + + UniValue v((int64_t)1023LL); + BOOST_CHECK(arr.push_back(v)); + + string vStr("zippy"); + BOOST_CHECK(arr.push_back(vStr)); + + const char *s = "pippy"; + BOOST_CHECK(arr.push_back(s)); + + vector vec; + v.setStr("boing"); + vec.push_back(v); + + v.setStr("going"); + vec.push_back(v); + + BOOST_CHECK(arr.push_backV(vec)); + + BOOST_CHECK_EQUAL(arr.empty(), false); + BOOST_CHECK_EQUAL(arr.size(), 5); + + BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023"); + BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy"); + BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy"); + BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing"); + BOOST_CHECK_EQUAL(arr[4].getValStr(), "going"); + + BOOST_CHECK_EQUAL(arr[999].getValStr(), ""); + + arr.clear(); + BOOST_CHECK(arr.empty()); + BOOST_CHECK_EQUAL(arr.size(), 0); +} + +BOOST_AUTO_TEST_CASE(univalue_object) +{ + UniValue obj(UniValue::VOBJ); + string strKey, strVal; + UniValue v; + + strKey = "age"; + v.setInt(100); + BOOST_CHECK(obj.pushKV(strKey, v)); + + strKey = "first"; + strVal = "John"; + BOOST_CHECK(obj.pushKV(strKey, strVal)); + + strKey = "last"; + const char *cVal = "Smith"; + BOOST_CHECK(obj.pushKV(strKey, cVal)); + + strKey = "distance"; + BOOST_CHECK(obj.pushKV(strKey, (int64_t)25)); + + strKey = "time"; + BOOST_CHECK(obj.pushKV(strKey, (uint64_t)3600)); + + strKey = "calories"; + BOOST_CHECK(obj.pushKV(strKey, (int)12)); + + strKey = "temperature"; + BOOST_CHECK(obj.pushKV(strKey, (double)90.012)); + + UniValue obj2(UniValue::VOBJ); + BOOST_CHECK(obj2.pushKV("cat1", 9000)); + BOOST_CHECK(obj2.pushKV("cat2", 12345)); + + BOOST_CHECK(obj.pushKVs(obj2)); + + BOOST_CHECK_EQUAL(obj.empty(), false); + BOOST_CHECK_EQUAL(obj.size(), 9); + + BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100"); + BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John"); + BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith"); + BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25"); + BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600"); + BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12"); + BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012"); + BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000"); + BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345"); + + BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), ""); + + BOOST_CHECK(obj.exists("age")); + BOOST_CHECK(obj.exists("first")); + BOOST_CHECK(obj.exists("last")); + BOOST_CHECK(obj.exists("distance")); + BOOST_CHECK(obj.exists("time")); + BOOST_CHECK(obj.exists("calories")); + BOOST_CHECK(obj.exists("temperature")); + BOOST_CHECK(obj.exists("cat1")); + BOOST_CHECK(obj.exists("cat2")); + + BOOST_CHECK(!obj.exists("nyuknyuknyuk")); + + map objTypes; + objTypes["age"] = UniValue::VNUM; + objTypes["first"] = UniValue::VSTR; + objTypes["last"] = UniValue::VSTR; + objTypes["distance"] = UniValue::VNUM; + objTypes["time"] = UniValue::VNUM; + objTypes["calories"] = UniValue::VNUM; + objTypes["temperature"] = UniValue::VNUM; + objTypes["cat1"] = UniValue::VNUM; + objTypes["cat2"] = UniValue::VNUM; + BOOST_CHECK(obj.checkObject(objTypes)); + + objTypes["cat2"] = UniValue::VSTR; + BOOST_CHECK(!obj.checkObject(objTypes)); + + obj.clear(); + BOOST_CHECK(obj.empty()); + BOOST_CHECK_EQUAL(obj.size(), 0); +} + +static const char *json1 = + "[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]"; + +BOOST_AUTO_TEST_CASE(univalue_readwrite) +{ + UniValue v; + BOOST_CHECK(v.read(json1)); + + string strJson1(json1); + BOOST_CHECK(v.read(strJson1)); + + BOOST_CHECK(v.isArray()); + BOOST_CHECK_EQUAL(v.size(), 2); + + BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000"); + + UniValue obj = v[1]; + BOOST_CHECK(obj.isObject()); + BOOST_CHECK_EQUAL(obj.size(), 3); + + BOOST_CHECK(obj["key1"].isStr()); + std::string correctValue("str"); + correctValue.push_back('\0'); + BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue); + BOOST_CHECK(obj["key2"].isNum()); + BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800"); + BOOST_CHECK(obj["key3"].isObject()); + + BOOST_CHECK_EQUAL(strJson1, v.write()); + + /* Check for (correctly reporting) a parsing error if the initial + JSON construct is followed by more stuff. Note that whitespace + is, of course, exempt. */ + + BOOST_CHECK(v.read(" {}\n ")); + BOOST_CHECK(v.isObject()); + BOOST_CHECK(v.read(" []\n ")); + BOOST_CHECK(v.isArray()); + + BOOST_CHECK(!v.read("@{}")); + BOOST_CHECK(!v.read("{} garbage")); + BOOST_CHECK(!v.read("[]{}")); + BOOST_CHECK(!v.read("{}[]")); + BOOST_CHECK(!v.read("{} 42")); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 121274b7..4556b52e 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1,72 +1,172 @@ -#include -#include +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "main.h" -#include "wallet.h" #include "util.h" +#include "clientversion.h" +#include "primitives/transaction.h" +#include "random.h" +#include "sync.h" +#include "test/test_bitcoin.h" +#include "utilmoneystr.h" +#include "utilstrencodings.h" + +#include +#include + +#include + using namespace std; -BOOST_AUTO_TEST_SUITE(util_tests) +BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(util_criticalsection) { CCriticalSection cs; - do { + do + { LOCK(cs); break; BOOST_ERROR("break was swallowed!"); - } while(0); + } while (0); - do { + do + { TRY_LOCK(cs, lockTest); if (lockTest) break; BOOST_ERROR("break was swallowed!"); - } while(0); + } while (0); +} + + +static volatile int critVal = 0; +static volatile int readVal = 0; +static volatile bool threadExited = false; +static volatile bool threadStarted = false; +void ThreadSharedCritTest(CSharedCriticalSection *cs) +{ + threadStarted = true; + READLOCK(*cs); + readVal = critVal; + + threadExited = true; } -BOOST_AUTO_TEST_CASE(util_MedianFilter) -{ - CMedianFilter filter(5, 15); +BOOST_AUTO_TEST_CASE(util_sharedcriticalsection) +{ + CSharedCriticalSection cs; + + do + { + READLOCK(cs); + break; + + BOOST_ERROR("break was swallowed!"); + } while (0); + + do + { + WRITELOCK(cs); + break; + + BOOST_ERROR("break was swallowed!"); + } while (0); + + { // If the read lock does not allow simultaneous locking, this code will hang in the join_all + boost::thread_group thrds; + READLOCK(cs); + thrds.create_thread(boost::bind(ThreadSharedCritTest, &cs)); + thrds.join_all(); + } + + { // Ensure that the exclusive lock works + threadStarted = false; + threadExited = false; + readVal = 0; + critVal = 1; + boost::thread_group thrds; + { + WRITELOCK(cs); + thrds.create_thread(boost::bind(ThreadSharedCritTest, &cs)); + MilliSleep(250); // give thread a chance to run. + BOOST_CHECK(threadStarted == true); + BOOST_CHECK(threadExited == false); + critVal = 2; + } + // Now the write lock is released so the thread should read the value. + thrds.join_all(); + BOOST_CHECK(threadExited == true); + BOOST_CHECK(readVal == 2); + } +} - BOOST_CHECK_EQUAL(filter.median(), 15); - filter.input(20); // [15 20] - BOOST_CHECK_EQUAL(filter.median(), 17); +void ThreadCorralTest(CThreadCorral *c, int region, int *readVal, int setVal) +{ + CORRAL(*c, region); + *readVal = critVal; + if (setVal != 0) + critVal = setVal; +} - filter.input(30); // [15 20 30] - BOOST_CHECK_EQUAL(filter.median(), 20); - filter.input(3); // [3 15 20 30] - BOOST_CHECK_EQUAL(filter.median(), 17); +BOOST_AUTO_TEST_CASE(util_threadcorral) +{ + CThreadCorral corral; + + { // ensure that regions lock out other regions, but not the current region. + boost::thread_group thrds; + int readVals[3] = {0, 0, 0}; + { + CORRAL(corral, 1); + critVal = 1; + thrds.create_thread(boost::bind(ThreadCorralTest, &corral, 0, &readVals[0], 4)); + thrds.create_thread(boost::bind(ThreadCorralTest, &corral, 1, &readVals[1], 0)); + MilliSleep(500); // Thread 1 should run now because there is no higher region waiting. + thrds.create_thread(boost::bind(ThreadCorralTest, &corral, 2, &readVals[2], 3)); + MilliSleep(500); // give threads a chance to run (if they are going to). + critVal = 2; + } + MilliSleep(1000); // give threads a chance to run (if they are going to). + BOOST_CHECK(readVals[1] == 1); // since region 1 was active, thread 1 should have run right away + BOOST_CHECK(readVals[2] == 2); // After release, region 2 should have run since its higher priority + BOOST_CHECK(readVals[0] == 3); // Finally, region 0 should have run (and gotten the value set by region 2) + } +} - filter.input(7); // [3 7 15 20 30] - BOOST_CHECK_EQUAL(filter.median(), 15); - filter.input(18); // [3 7 18 20 30] - BOOST_CHECK_EQUAL(filter.median(), 18); +static const unsigned char ParseHex_expected[65] = {0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, + 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, + 0x61, 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, + 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f}; - filter.input(0); // [0 3 7 18 30] - BOOST_CHECK_EQUAL(filter.median(), 7); +BOOST_AUTO_TEST_CASE(util_DbgAssert) +{ +#ifndef DEBUG_ASSERTION + int i = 0; + bool savedVal = fPrintToConsole; + fPrintToConsole = true; + DbgAssert(1, i = 1); + BOOST_CHECK(i == 0); + DbgAssert(0, i = 1); + BOOST_CHECK(i == 1); + fPrintToConsole = savedVal; +#endif } -static const unsigned char ParseHex_expected[65] = { - 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, - 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, - 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, - 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, - 0x5f -}; BOOST_AUTO_TEST_CASE(util_ParseHex) { std::vector result; std::vector expected(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected)); // Basic test vector - result = ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"); + result = ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112" + "de5c384df7ba0b8d578a4c702b6bf11d5f"); BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); // Spaces between bytes must be supported @@ -80,59 +180,52 @@ BOOST_AUTO_TEST_CASE(util_ParseHex) BOOST_AUTO_TEST_CASE(util_HexStr) { - BOOST_CHECK_EQUAL( - HexStr(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected)), - "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"); + BOOST_CHECK_EQUAL(HexStr(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected)), + "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b" + "8d578a4c702b6bf11d5f"); - BOOST_CHECK_EQUAL( - HexStr(ParseHex_expected, ParseHex_expected + 5, true), - "04 67 8a fd b0"); + BOOST_CHECK_EQUAL(HexStr(ParseHex_expected, ParseHex_expected + 5, true), "04 67 8a fd b0"); - BOOST_CHECK_EQUAL( - HexStr(ParseHex_expected, ParseHex_expected, true), - ""); + BOOST_CHECK_EQUAL(HexStr(ParseHex_expected, ParseHex_expected, true), ""); std::vector ParseHex_vec(ParseHex_expected, ParseHex_expected + 5); - BOOST_CHECK_EQUAL( - HexStr(ParseHex_vec, true), - "04 67 8a fd b0"); + BOOST_CHECK_EQUAL(HexStr(ParseHex_vec, true), "04 67 8a fd b0"); } BOOST_AUTO_TEST_CASE(util_DateTimeStrFormat) { -/*These are platform-dependant and thus removed to avoid useless test failures - BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0), "01/01/70 00:00:00"); - BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0x7FFFFFFF), "01/19/38 03:14:07"); - // Formats used within Bitcoin - BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 1317425777), "09/30/11 23:36:17"); - BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M", 1317425777), "09/30/11 23:36"); -*/ + BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 0), "1970-01-01 00:00:00"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 0x7FFFFFFF), "2038-01-19 03:14:07"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 1317425777), "2011-09-30 23:36:17"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M", 1317425777), "2011-09-30 23:36"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", 1317425777), "Fri, 30 Sep 2011 23:36:17 +0000"); } BOOST_AUTO_TEST_CASE(util_ParseParameters) { - const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"}; + const char *argv_test[] = { + "-ignored", "-reindex", "-txindex", "-connect=argument", "-connect=multiple", "f", "-d=e"}; - ParseParameters(0, (char**)argv_test); + ParseParameters(0, (char **)argv_test, AllowedArgs::Bitcoind()); BOOST_CHECK(mapArgs.empty() && mapMultiArgs.empty()); - ParseParameters(1, (char**)argv_test); + ParseParameters(1, (char **)argv_test, AllowedArgs::Bitcoind()); BOOST_CHECK(mapArgs.empty() && mapMultiArgs.empty()); - ParseParameters(5, (char**)argv_test); - // expectation: -ignored is ignored (program name argument), - // -a, -b and -ccc end up in map, -d ignored because it is after + ParseParameters(5, (char **)argv_test, AllowedArgs::Bitcoind()); + // expectation: -ignored is ignored (program name argument), + // -reindex, -txindex and -connect end up in map, -d ignored because it is after // a non-option argument (non-GNU option parsing) BOOST_CHECK(mapArgs.size() == 3 && mapMultiArgs.size() == 3); - BOOST_CHECK(mapArgs.count("-a") && mapArgs.count("-b") && mapArgs.count("-ccc") - && !mapArgs.count("f") && !mapArgs.count("-d")); - BOOST_CHECK(mapMultiArgs.count("-a") && mapMultiArgs.count("-b") && mapMultiArgs.count("-ccc") - && !mapMultiArgs.count("f") && !mapMultiArgs.count("-d")); + BOOST_CHECK(mapArgs.count("-reindex") && mapArgs.count("-txindex") && mapArgs.count("-connect") && + !mapArgs.count("f") && !mapArgs.count("-d")); + BOOST_CHECK(mapMultiArgs.count("-reindex") && mapMultiArgs.count("-txindex") && mapMultiArgs.count("-connect") && + !mapMultiArgs.count("f") && !mapMultiArgs.count("-d")); - BOOST_CHECK(mapArgs["-a"] == "" && mapArgs["-ccc"] == "multiple"); - BOOST_CHECK(mapMultiArgs["-ccc"].size() == 2); + BOOST_CHECK(mapArgs["-reindex"] == "" && mapArgs["-connect"] == "multiple"); + BOOST_CHECK(mapMultiArgs["-connect"].size() == 2); } BOOST_AUTO_TEST_CASE(util_GetArg) @@ -153,96 +246,88 @@ BOOST_AUTO_TEST_CASE(util_GetArg) BOOST_CHECK_EQUAL(GetArg("inttest1", -1), 12345); BOOST_CHECK_EQUAL(GetArg("inttest2", -1), 81985529216486895LL); BOOST_CHECK_EQUAL(GetArg("inttest3", -1), -1); - BOOST_CHECK_EQUAL(GetBoolArg("booltest1"), true); - BOOST_CHECK_EQUAL(GetBoolArg("booltest2"), false); - BOOST_CHECK_EQUAL(GetBoolArg("booltest3"), false); - BOOST_CHECK_EQUAL(GetBoolArg("booltest4"), true); -} - -BOOST_AUTO_TEST_CASE(util_WildcardMatch) -{ - BOOST_CHECK(WildcardMatch("127.0.0.1", "*")); - BOOST_CHECK(WildcardMatch("127.0.0.1", "127.*")); - BOOST_CHECK(WildcardMatch("abcdef", "a?cde?")); - BOOST_CHECK(!WildcardMatch("abcdef", "a?cde??")); - BOOST_CHECK(WildcardMatch("abcdef", "a*f")); - BOOST_CHECK(!WildcardMatch("abcdef", "a*x")); - BOOST_CHECK(WildcardMatch("", "*")); + BOOST_CHECK_EQUAL(GetBoolArg("booltest1", false), true); + BOOST_CHECK_EQUAL(GetBoolArg("booltest2", false), false); + BOOST_CHECK_EQUAL(GetBoolArg("booltest3", false), false); + BOOST_CHECK_EQUAL(GetBoolArg("booltest4", false), true); } BOOST_AUTO_TEST_CASE(util_FormatMoney) { - BOOST_CHECK_EQUAL(FormatMoney(0, false), "0.00"); - BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789, false), "12345.6789"); - BOOST_CHECK_EQUAL(FormatMoney(COIN, true), "+1.00"); - BOOST_CHECK_EQUAL(FormatMoney(-COIN, false), "-1.00"); - BOOST_CHECK_EQUAL(FormatMoney(-COIN, true), "-1.00"); - - BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000, false), "100000000.00"); - BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000, false), "10000000.00"); - BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000, false), "1000000.00"); - BOOST_CHECK_EQUAL(FormatMoney(COIN*100000, false), "100000.00"); - BOOST_CHECK_EQUAL(FormatMoney(COIN*10000, false), "10000.00"); - BOOST_CHECK_EQUAL(FormatMoney(COIN*1000, false), "1000.00"); - BOOST_CHECK_EQUAL(FormatMoney(COIN*100, false), "100.00"); - BOOST_CHECK_EQUAL(FormatMoney(COIN*10, false), "10.00"); - BOOST_CHECK_EQUAL(FormatMoney(COIN, false), "1.00"); - BOOST_CHECK_EQUAL(FormatMoney(COIN/10, false), "0.10"); - BOOST_CHECK_EQUAL(FormatMoney(COIN/100, false), "0.01"); - BOOST_CHECK_EQUAL(FormatMoney(COIN/1000, false), "0.001"); - BOOST_CHECK_EQUAL(FormatMoney(COIN/10000, false), "0.0001"); - BOOST_CHECK_EQUAL(FormatMoney(COIN/100000, false), "0.00001"); - BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000, false), "0.000001"); - BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000, false), "0.0000001"); - BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000, false), "0.00000001"); + BOOST_CHECK_EQUAL(FormatMoney(0), "0.00"); + BOOST_CHECK_EQUAL(FormatMoney((COIN / 10000) * 123456789), "12345.6789"); + BOOST_CHECK_EQUAL(FormatMoney(-COIN), "-1.00"); + + BOOST_CHECK_EQUAL(FormatMoney(COIN * 100000000), "100000000.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN * 10000000), "10000000.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN * 1000000), "1000000.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN * 100000), "100000.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN * 10000), "10000.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN * 1000), "1000.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN * 100), "100.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN * 10), "10.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN), "1.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN / 10), "0.10"); + BOOST_CHECK_EQUAL(FormatMoney(COIN / 100), "0.01"); + BOOST_CHECK_EQUAL(FormatMoney(COIN / 1000), "0.001"); + BOOST_CHECK_EQUAL(FormatMoney(COIN / 10000), "0.0001"); + BOOST_CHECK_EQUAL(FormatMoney(COIN / 100000), "0.00001"); + BOOST_CHECK_EQUAL(FormatMoney(COIN / 1000000), "0.000001"); + BOOST_CHECK_EQUAL(FormatMoney(COIN / 10000000), "0.0000001"); + BOOST_CHECK_EQUAL(FormatMoney(COIN / 100000000), "0.00000001"); } BOOST_AUTO_TEST_CASE(util_ParseMoney) { - int64 ret = 0; + CAmount ret = 0; BOOST_CHECK(ParseMoney("0.0", ret)); BOOST_CHECK_EQUAL(ret, 0); BOOST_CHECK(ParseMoney("12345.6789", ret)); - BOOST_CHECK_EQUAL(ret, (COIN/10000)*123456789); + BOOST_CHECK_EQUAL(ret, (COIN / 10000) * 123456789); BOOST_CHECK(ParseMoney("100000000.00", ret)); - BOOST_CHECK_EQUAL(ret, COIN*100000000); + BOOST_CHECK_EQUAL(ret, COIN * 100000000); BOOST_CHECK(ParseMoney("10000000.00", ret)); - BOOST_CHECK_EQUAL(ret, COIN*10000000); + BOOST_CHECK_EQUAL(ret, COIN * 10000000); BOOST_CHECK(ParseMoney("1000000.00", ret)); - BOOST_CHECK_EQUAL(ret, COIN*1000000); + BOOST_CHECK_EQUAL(ret, COIN * 1000000); BOOST_CHECK(ParseMoney("100000.00", ret)); - BOOST_CHECK_EQUAL(ret, COIN*100000); + BOOST_CHECK_EQUAL(ret, COIN * 100000); BOOST_CHECK(ParseMoney("10000.00", ret)); - BOOST_CHECK_EQUAL(ret, COIN*10000); + BOOST_CHECK_EQUAL(ret, COIN * 10000); BOOST_CHECK(ParseMoney("1000.00", ret)); - BOOST_CHECK_EQUAL(ret, COIN*1000); + BOOST_CHECK_EQUAL(ret, COIN * 1000); BOOST_CHECK(ParseMoney("100.00", ret)); - BOOST_CHECK_EQUAL(ret, COIN*100); + BOOST_CHECK_EQUAL(ret, COIN * 100); BOOST_CHECK(ParseMoney("10.00", ret)); - BOOST_CHECK_EQUAL(ret, COIN*10); + 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_EQUAL(ret, COIN / 10); BOOST_CHECK(ParseMoney("0.01", ret)); - BOOST_CHECK_EQUAL(ret, COIN/100); + BOOST_CHECK_EQUAL(ret, COIN / 100); BOOST_CHECK(ParseMoney("0.001", ret)); - BOOST_CHECK_EQUAL(ret, COIN/1000); + BOOST_CHECK_EQUAL(ret, COIN / 1000); BOOST_CHECK(ParseMoney("0.0001", ret)); - BOOST_CHECK_EQUAL(ret, COIN/10000); + BOOST_CHECK_EQUAL(ret, COIN / 10000); BOOST_CHECK(ParseMoney("0.00001", ret)); - BOOST_CHECK_EQUAL(ret, COIN/100000); + BOOST_CHECK_EQUAL(ret, COIN / 100000); BOOST_CHECK(ParseMoney("0.000001", ret)); - BOOST_CHECK_EQUAL(ret, COIN/1000000); + BOOST_CHECK_EQUAL(ret, COIN / 1000000); BOOST_CHECK(ParseMoney("0.0000001", ret)); - BOOST_CHECK_EQUAL(ret, COIN/10000000); + BOOST_CHECK_EQUAL(ret, COIN / 10000000); BOOST_CHECK(ParseMoney("0.00000001", ret)); - BOOST_CHECK_EQUAL(ret, COIN/100000000); + BOOST_CHECK_EQUAL(ret, COIN / 100000000); // 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) @@ -260,4 +345,371 @@ BOOST_AUTO_TEST_CASE(util_IsHex) BOOST_CHECK(!IsHex("0x0000")); } +BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) +{ + int i; + int count = 0; + + seed_insecure_rand(true); + + for (int mod = 2; mod < 11; mod++) + { + int mask = 1; + // Really rough binomal confidence approximation. + int err = 30 * 10000. / mod * sqrt((1. / mod * (1 - 1. / mod)) / 10000.); + // mask is 2^ceil(log2(mod))-1 + while (mask < mod - 1) + mask = (mask << 1) + 1; + + count = 0; + // How often does it get a zero from the uniform range [0,mod)? + for (i = 0; i < 10000; i++) + { + uint32_t rval; + do + { + rval = insecure_rand() & mask; + } while (rval >= (uint32_t)mod); + count += rval == 0; + } + BOOST_CHECK(count <= 10000 / mod + err); + BOOST_CHECK(count >= 10000 / mod - err); + } +} + +BOOST_AUTO_TEST_CASE(util_TimingResistantEqual) +{ + BOOST_CHECK(TimingResistantEqual(std::string(""), std::string(""))); + BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string(""))); + BOOST_CHECK(!TimingResistantEqual(std::string(""), std::string("abc"))); + BOOST_CHECK(!TimingResistantEqual(std::string("a"), std::string("aa"))); + BOOST_CHECK(!TimingResistantEqual(std::string("aa"), std::string("a"))); + BOOST_CHECK(TimingResistantEqual(std::string("abc"), std::string("abc"))); + BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string("aba"))); +} + +/* Test strprintf formatting directives. + * Put a string before and after to ensure sanity of element sizes on stack. */ +#define B "check_prefix" +#define E "check_postfix" +BOOST_AUTO_TEST_CASE(strprintf_numbers) +{ + int64_t s64t = -9223372036854775807LL; /* signed 64 bit test value */ + uint64_t u64t = 18446744073709551615ULL; /* unsigned 64 bit test value */ + BOOST_CHECK(strprintf("%s %d %s", B, s64t, E) == B " -9223372036854775807 " E); + BOOST_CHECK(strprintf("%s %u %s", B, u64t, E) == B " 18446744073709551615 " E); + BOOST_CHECK(strprintf("%s %x %s", B, u64t, E) == B " ffffffffffffffff " E); + + size_t st = 12345678; /* unsigned size_t test value */ + ssize_t sst = -12345678; /* signed size_t test value */ + BOOST_CHECK(strprintf("%s %d %s", B, sst, E) == B " -12345678 " E); + BOOST_CHECK(strprintf("%s %u %s", B, st, E) == B " 12345678 " E); + BOOST_CHECK(strprintf("%s %x %s", B, st, E) == B " bc614e " E); + + ptrdiff_t pt = 87654321; /* positive ptrdiff_t test value */ + ptrdiff_t spt = -87654321; /* negative ptrdiff_t test value */ + BOOST_CHECK(strprintf("%s %d %s", B, spt, E) == B " -87654321 " E); + BOOST_CHECK(strprintf("%s %u %s", B, pt, E) == B " 87654321 " E); + BOOST_CHECK(strprintf("%s %x %s", B, pt, E) == B " 5397fb1 " E); +} +#undef B +#undef E + +/* Check for mingw/wine issue #3494 + * Remove this test before time.ctime(0xffffffff) == 'Sun Feb 7 07:28:15 2106' + */ +BOOST_AUTO_TEST_CASE(gettime) { BOOST_CHECK((GetTime() & ~0xFFFFFFFFLL) == 0); } +BOOST_AUTO_TEST_CASE(test_ParseInt32) +{ + int32_t n; + // Valid values + BOOST_CHECK(ParseInt32("1234", NULL)); + BOOST_CHECK(ParseInt32("0", &n) && n == 0); + BOOST_CHECK(ParseInt32("1234", &n) && n == 1234); + BOOST_CHECK(ParseInt32("01234", &n) && n == 1234); // no octal + BOOST_CHECK(ParseInt32("2147483647", &n) && n == 2147483647); + BOOST_CHECK(ParseInt32("-2147483648", &n) && n == -2147483648); + BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234); + // Invalid values + BOOST_CHECK(!ParseInt32("", &n)); + BOOST_CHECK(!ParseInt32(" 1", &n)); // no padding inside + BOOST_CHECK(!ParseInt32("1 ", &n)); + BOOST_CHECK(!ParseInt32("1a", &n)); + BOOST_CHECK(!ParseInt32("aap", &n)); + BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex + BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex + const char test_bytes[] = {'1', 0, '1'}; + std::string teststr(test_bytes, sizeof(test_bytes)); + BOOST_CHECK(!ParseInt32(teststr, &n)); // no embedded NULs + // Overflow and underflow + BOOST_CHECK(!ParseInt32("-2147483649", NULL)); + BOOST_CHECK(!ParseInt32("2147483648", NULL)); + BOOST_CHECK(!ParseInt32("-32482348723847471234", NULL)); + BOOST_CHECK(!ParseInt32("32482348723847471234", NULL)); +} + +BOOST_AUTO_TEST_CASE(test_ParseInt64) +{ + int64_t n; + // Valid values + BOOST_CHECK(ParseInt64("1234", NULL)); + BOOST_CHECK(ParseInt64("0", &n) && n == 0LL); + BOOST_CHECK(ParseInt64("1234", &n) && n == 1234LL); + BOOST_CHECK(ParseInt64("01234", &n) && n == 1234LL); // no octal + BOOST_CHECK(ParseInt64("2147483647", &n) && n == 2147483647LL); + BOOST_CHECK(ParseInt64("-2147483648", &n) && n == -2147483648LL); + BOOST_CHECK(ParseInt64("9223372036854775807", &n) && n == (int64_t)9223372036854775807); + BOOST_CHECK(ParseInt64("-9223372036854775808", &n) && n == (int64_t)-9223372036854775807 - 1); + BOOST_CHECK(ParseInt64("-1234", &n) && n == -1234LL); + // Invalid values + BOOST_CHECK(!ParseInt64("", &n)); + BOOST_CHECK(!ParseInt64(" 1", &n)); // no padding inside + BOOST_CHECK(!ParseInt64("1 ", &n)); + BOOST_CHECK(!ParseInt64("1a", &n)); + BOOST_CHECK(!ParseInt64("aap", &n)); + BOOST_CHECK(!ParseInt64("0x1", &n)); // no hex + const char test_bytes[] = {'1', 0, '1'}; + std::string teststr(test_bytes, sizeof(test_bytes)); + BOOST_CHECK(!ParseInt64(teststr, &n)); // no embedded NULs + // Overflow and underflow + BOOST_CHECK(!ParseInt64("-9223372036854775809", NULL)); + BOOST_CHECK(!ParseInt64("9223372036854775808", NULL)); + BOOST_CHECK(!ParseInt64("-32482348723847471234", NULL)); + BOOST_CHECK(!ParseInt64("32482348723847471234", NULL)); +} + +BOOST_AUTO_TEST_CASE(test_ParseDouble) +{ + double n; + // Valid values + BOOST_CHECK(ParseDouble("1234", NULL)); + BOOST_CHECK(ParseDouble("0", &n) && n == 0.0); + BOOST_CHECK(ParseDouble("1234", &n) && n == 1234.0); + BOOST_CHECK(ParseDouble("01234", &n) && n == 1234.0); // no octal + BOOST_CHECK(ParseDouble("2147483647", &n) && n == 2147483647.0); + BOOST_CHECK(ParseDouble("-2147483648", &n) && n == -2147483648.0); + BOOST_CHECK(ParseDouble("-1234", &n) && n == -1234.0); + BOOST_CHECK(ParseDouble("1e6", &n) && n == 1e6); + BOOST_CHECK(ParseDouble("-1e6", &n) && n == -1e6); + // Invalid values + BOOST_CHECK(!ParseDouble("", &n)); + BOOST_CHECK(!ParseDouble(" 1", &n)); // no padding inside + BOOST_CHECK(!ParseDouble("1 ", &n)); + BOOST_CHECK(!ParseDouble("1a", &n)); + BOOST_CHECK(!ParseDouble("aap", &n)); + BOOST_CHECK(!ParseDouble("0x1", &n)); // no hex + const char test_bytes[] = {'1', 0, '1'}; + std::string teststr(test_bytes, sizeof(test_bytes)); + BOOST_CHECK(!ParseDouble(teststr, &n)); // no embedded NULs + // Overflow and underflow + BOOST_CHECK(!ParseDouble("-1e10000", NULL)); + BOOST_CHECK(!ParseDouble("1e10000", NULL)); +} + +BOOST_AUTO_TEST_CASE(test_FormatParagraph) +{ + BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), ""); + BOOST_CHECK_EQUAL(FormatParagraph("test", 79, 0), "test"); + BOOST_CHECK_EQUAL(FormatParagraph(" test", 79, 0), " test"); + BOOST_CHECK_EQUAL(FormatParagraph("test test", 79, 0), "test test"); + BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 0), "test\ntest"); + BOOST_CHECK_EQUAL(FormatParagraph("testerde test", 4, 0), "testerde\ntest"); + BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 4), "test\n test"); + + // Make sure we don't indent a fully-new line following a too-long line ending + BOOST_CHECK_EQUAL(FormatParagraph("test test\nabc", 4, 4), "test\n test\nabc"); + + BOOST_CHECK_EQUAL(FormatParagraph("This_is_a_very_long_test_string_without_any_spaces_so_it_should_just_get_" + "returned_as_is_despite_the_length until it gets here", + 79), + "This_is_a_very_long_test_string_without_any_spaces_so_it_should_just_get_returned_as_is_despite_the_" + "length\nuntil it gets here"); + + // Test wrap length is exact + BOOST_CHECK_EQUAL( + FormatParagraph( + "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p", 79), + "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de\nf g h i j k l m n o p"); + BOOST_CHECK_EQUAL( + FormatParagraph( + "x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p", + 79), + "x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de\nf g h i j k l m n o p"); + // Indent should be included in length of lines + BOOST_CHECK_EQUAL( + FormatParagraph("x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k " + "l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 a b c d e fg h i j k", + 79, 4), + "x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de\n f g h i j k l m n o p " + "q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 a b c d e fg\n h i j k"); + + BOOST_CHECK_EQUAL( + FormatParagraph("This is a very long test string. This is a second sentence in the very long test string.", 79), + "This is a very long test string. This is a second sentence in the very long\ntest string."); + BOOST_CHECK_EQUAL(FormatParagraph("This is a very long test string.\nThis is a second sentence in the very long " + "test string. This is a third sentence in the very long test string.", + 79), + "This is a very long test string.\nThis is a second sentence in the very long test string. This is a " + "third\nsentence in the very long test string."); + BOOST_CHECK_EQUAL(FormatParagraph("This is a very long test string.\n\nThis is a second sentence in the very long " + "test string. This is a third sentence in the very long test string.", + 79), + "This is a very long test string.\n\nThis is a second sentence in the very long test string. This is a " + "third\nsentence in the very long test string."); + BOOST_CHECK_EQUAL(FormatParagraph("Testing that normal newlines do not get indented.\nLike here.", 79), + "Testing that normal newlines do not get indented.\nLike here."); +} + +BOOST_AUTO_TEST_CASE(test_FormatSubVersion) +{ + std::vector comments; + comments.push_back(std::string("comment1")); + std::vector comments2; + comments2.push_back(std::string("comment1")); + // Semicolon is discouraged but not forbidden by BIP-0014 + comments2.push_back( + SanitizeString(std::string("Comment2; .,_?@-; !\"#$%&'()*+/<=>[]\\^`{|}~"), SAFE_CHARS_UA_COMMENT)); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector()), std::string("/Test:0.9.99/")); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments), std::string("/Test:0.9.99(comment1)/")); + BOOST_CHECK_EQUAL( + FormatSubVersion("Test", 99900, comments2), std::string("/Test:0.9.99(comment1; Comment2; .,_?@-; )/")); +} + +BOOST_AUTO_TEST_CASE(test_ParseFixedPoint) +{ + int64_t amount = 0; + BOOST_CHECK(ParseFixedPoint("0", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 0LL); + BOOST_CHECK(ParseFixedPoint("1", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 100000000LL); + BOOST_CHECK(ParseFixedPoint("0.0", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 0LL); + BOOST_CHECK(ParseFixedPoint("-0.1", 8, &amount)); + BOOST_CHECK_EQUAL(amount, -10000000LL); + BOOST_CHECK(ParseFixedPoint("1.1", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 110000000LL); + BOOST_CHECK(ParseFixedPoint("1.10000000000000000", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 110000000LL); + BOOST_CHECK(ParseFixedPoint("1.1e1", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 1100000000LL); + BOOST_CHECK(ParseFixedPoint("1.1e-1", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 11000000LL); + BOOST_CHECK(ParseFixedPoint("1000", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 100000000000LL); + BOOST_CHECK(ParseFixedPoint("-1000", 8, &amount)); + BOOST_CHECK_EQUAL(amount, -100000000000LL); + BOOST_CHECK(ParseFixedPoint("0.00000001", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 1LL); + BOOST_CHECK(ParseFixedPoint("0.0000000100000000", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 1LL); + BOOST_CHECK(ParseFixedPoint("-0.00000001", 8, &amount)); + BOOST_CHECK_EQUAL(amount, -1LL); + BOOST_CHECK(ParseFixedPoint("1000000000.00000001", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 100000000000000001LL); + BOOST_CHECK(ParseFixedPoint("9999999999.99999999", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 999999999999999999LL); + BOOST_CHECK(ParseFixedPoint("-9999999999.99999999", 8, &amount)); + BOOST_CHECK_EQUAL(amount, -999999999999999999LL); + + BOOST_CHECK(!ParseFixedPoint("", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("a-1000", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-a1000", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-1000a", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-01000", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("00.1", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint(".1", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("--0.1", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("0.000000001", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-0.000000001", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("0.00000001000000001", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-10000000000.00000000", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("10000000000.00000000", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-10000000000.00000001", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("10000000000.00000001", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-10000000000.00000009", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("10000000000.00000009", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-99999999999.99999999", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("99999909999.09999999", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("92233720368.54775807", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("92233720368.54775808", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-92233720368.54775808", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-92233720368.54775809", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("1.1e", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("1.1e-", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("1.", 8, &amount)); +} + +// Log tests: +bool TestSetLog(uint64_t categoriesExpected, const char *arg1, const char *arg2 = NULL) +{ + UniValue logargs(UniValue::VARR); + bool ret = false; + logargs.push_back(arg1); + if (arg2 != NULL) + logargs.push_back(arg2); + + setlog(logargs, false); // The function to be tested + + if (categoriesExpected == Logging::categoriesEnabled) + ret = true; + + // LOGA("TestSetLog %s %s ret: %d\n", arg1, ((arg2 == NULL)?"":arg2),(int)ret); + return ret; +} + +bool IsStringTrueBadArgTest(const char *arg1) +{ + try + { + IsStringTrue(arg1); + } + catch (...) + { + return true; // If bad arg return true + } + return false; +} + +BOOST_AUTO_TEST_CASE(util_Logging) +{ + { + using namespace Logging; + BOOST_CHECK_EQUAL(8, sizeof(categoriesEnabled)); + BOOST_CHECK_EQUAL(NONE, categoriesEnabled); + LogToggleCategory(THN, true); + BOOST_CHECK(LogAcceptCategory(THN)); + LogToggleCategory(THN, false); + BOOST_CHECK(!LogAcceptCategory(THN)); + LogToggleCategory(THN, true); + LogToggleCategory(NET, true); + BOOST_CHECK(LogAcceptCategory(THN | NET)); + LogToggleCategory(ALL, true); + BOOST_CHECK_EQUAL(ALL, categoriesEnabled); + LogToggleCategory(ALL, false); + BOOST_CHECK_EQUAL(NONE, categoriesEnabled); + BOOST_CHECK_EQUAL(LogGetLabel(ADR), "ADR"); + BOOST_CHECK(TestSetLog(ALL, "all", "on")); + BOOST_CHECK(TestSetLog(NONE, "all", "off")); + BOOST_CHECK(TestSetLog(NONE, "tor")); + BOOST_CHECK(TestSetLog(TOR, "tor", "on")); + BOOST_CHECK(TestSetLog(NONE, "tor", "off")); + BOOST_CHECK(!TestSetLog(TOR, "tor", "bad-arg")); + BOOST_CHECK(TestSetLog(categoriesEnabled, "badcategory", "on")); + LogToggleCategory(ALL, true); + LOG(THN, "missing args %s %d\n"); + LOG(THN, "wrong order args %s %d\n", 3, "hello"); + LOG(THN, "null arg %s\n", NULL); + BOOST_CHECK(IsStringTrue("true")); + BOOST_CHECK(IsStringTrue("enable")); + BOOST_CHECK(IsStringTrue("1")); + BOOST_CHECK(IsStringTrue("on")); + BOOST_CHECK(!IsStringTrue("false")); + BOOST_CHECK(!IsStringTrue("disable")); + BOOST_CHECK(!IsStringTrue("0")); + BOOST_CHECK(!IsStringTrue("off")); + BOOST_CHECK(IsStringTrueBadArgTest("bad")); + } +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp new file mode 100644 index 00000000..1e69ef94 --- /dev/null +++ b/src/test/versionbits_tests.cpp @@ -0,0 +1,400 @@ +// Copyright (c) 2014-2015 The Bitcoin Core developers +// Copyright (c) 2015-2017 The Bitcoin Unlimited developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "versionbits.h" +#include "chain.h" +#include "chainparams.h" +#include "consensus/params.h" +#include "main.h" +#include "random.h" +#include "test/test_bitcoin.h" + +#include + +/* 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 ¶ms) const { return TestTime(10000); } + int64_t EndTime(const Consensus::Params ¶ms) const { return TestTime(20000); } + int Period(const Consensus::Params ¶ms) const { return 1000; } + int Threshold(const Consensus::Params ¶ms) const { return 900; } + bool Condition(const CBlockIndex *pindex, const Consensus::Params ¶ms) 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 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() + // One second more and it would be defined + .Mine(1000, TestTime(10000) - 1, 0x100) + .TestDefined() + .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() + // One second more and it would be defined + .Mine(1000, TestTime(10000) - 1, 0x101) + .TestDefined() + .Mine(2000, TestTime(10000), 0x101) + .TestStarted() // So that's what happens the next period + .Mine(2999, TestTime(30000), 0x100) + .TestStarted() // 999 new blocks + // 1 new block (so 1000 out of the past 1000 are new) + .Mine(3000, TestTime(30000), 0x100) + .TestFailed() + .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() + // One second more and it would be defined + .Mine(1000, TestTime(10000) - 1, 0x101) + .TestDefined() + .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 + // 1 old block (so 900 out of the past 1000) + .Mine(3000, TestTime(29999), 0x200) + .TestLockedIn() + .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/timedata.cpp b/src/timedata.cpp index e5fb0804..935b7773 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -7,8 +7,8 @@ #include "netbase.h" #include "sync.h" #include "ui_interface.h" -#include "util.h" -#include "utilstrencodings.h" +#include "util/util.h" +#include "util/utilstrencodings.h" static CCriticalSection cs_nTimeOffset; static int64_t nTimeOffset = 0; diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 5e7a10aa..2824dcd7 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -1,7 +1,7 @@ #include "torcontrol.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include "net.h" -#include "util.h" +#include "util/util.h" #include "args.h" #include "crypto/hmac_sha256.h" diff --git a/src/tx/outpoint.h b/src/tx/outpoint.h new file mode 100644 index 00000000..f24639ce --- /dev/null +++ b/src/tx/outpoint.h @@ -0,0 +1,46 @@ +#ifndef OUTPOINT_H +#define OUTPOINT_H + +#include "serialize.h" +#include "uint256.h" + +/** An outpoint - a combination of a transaction hash and an index n into its vout */ +class COutPoint +{ +public: + uint256 hash; + uint32_t n; + + COutPoint() { SetNull(); } + COutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; } + + ADD_SERIALIZE_METHODS + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(hash); + READWRITE(n); + } + + void SetNull() { hash.SetNull(); n = (uint32_t) -1; } + bool IsNull() const { return (hash.IsNull() && n == (uint32_t) -1); } + + friend bool operator<(const COutPoint& a, const COutPoint& b) + { + return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n)); + } + + friend bool operator==(const COutPoint& a, const COutPoint& b) + { + return (a.hash == b.hash && a.n == b.n); + } + + friend bool operator!=(const COutPoint& a, const COutPoint& b) + { + return !(a == b); + } + + std::string ToString() const; +}; + +#endif // OUTPOINT_H diff --git a/src/tx/servicetx.cpp b/src/tx/servicetx.cpp new file mode 100644 index 00000000..88453fd7 --- /dev/null +++ b/src/tx/servicetx.cpp @@ -0,0 +1,90 @@ +// Copyright (c) 2017 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "servicetx.h" +#include "crypto/hash.h" +#include "streams.h" +#include "timedata.h" + +struct serializetx +{ + int32_t nVersion; + uint16_t nServiceId; + unsigned int nTime; + uint16_t nOpCode; + uint32_t nLockTime; + std::vector vdata; + + ADD_SERIALIZE_METHODS + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(*const_cast(&this->nVersion)); + nVersion = this->nVersion; + READWRITE(*const_cast(&this->nServiceId)); + READWRITE(*const_cast(&this->nTime)); + READWRITE(*const_cast(&this->nOpCode)); + READWRITE(*const_cast(&nLockTime)); + READWRITE(*const_cast*>(&vdata)); + } +}; + +uint256 CServiceTransaction::GetHash() const +{ + serializetx txtohash; + txtohash.nVersion = this->nVersion; + txtohash.nServiceId = this->nServiceId; + txtohash.nTime = this->nTime; + txtohash.nOpCode = this->nOpCode; + txtohash.nLockTime = this->nLockTime; + txtohash.vdata = this->vdata; + return SerializeHash(txtohash); +} + +void CServiceTransaction::UpdateHash() const +{ + serializetx txtohash; + txtohash.nVersion = this->nVersion; + txtohash.nServiceId = this->nServiceId; + txtohash.nTime = this->nTime; + txtohash.nOpCode = this->nOpCode; + txtohash.nLockTime = this->nLockTime; + txtohash.vdata = this->vdata; + *const_cast(&hash) = SerializeHash(txtohash); +} + +CServiceTransaction::CServiceTransaction() : nVersion(CServiceTransaction::CURRENT_VERSION), nServiceId(0), nTime(GetAdjustedTime()), nOpCode(0), nLockTime(0), vdata(), paymentReferenceHash(), securityHash() { + paymentReferenceHash.SetNull(); + securityHash.SetNull(); +} + +CServiceTransaction::CServiceTransaction(const CServiceTransaction &tx) : nVersion(tx.nVersion), nServiceId(tx.nServiceId), nTime(tx.nTime), nOpCode(tx.nOpCode), nLockTime(tx.nLockTime), vdata(tx.vdata), paymentReferenceHash(tx.paymentReferenceHash), securityHash(tx.securityHash) { + UpdateHash(); +} + +CServiceTransaction& CServiceTransaction::operator=(const CServiceTransaction &tx) { + *const_cast(&nVersion) = tx.nVersion; + *const_cast(&nServiceId) = tx.nServiceId; + *const_cast(&nTime) = tx.nTime; + *const_cast(&nOpCode) = tx.nOpCode; + *const_cast(&nLockTime) = tx.nLockTime; + *const_cast*>(&vdata) = tx.vdata; + *const_cast(&paymentReferenceHash) = tx.paymentReferenceHash; + *const_cast(&securityHash) = tx.securityHash; + *const_cast(&hash) = tx.hash; + return *this; +} + +std::string CServiceTransaction::ToString() const +{ + return ""; +} + +void CServiceTransaction::setSecurityHash() +{ + CDataStream ss(SER_GETHASH, 0); + ss << this->paymentReferenceHash; + ss << this->GetHash(); + securityHash = Hash(ss.begin(), ss.end()); +} diff --git a/src/tx/servicetx.h b/src/tx/servicetx.h new file mode 100644 index 00000000..b5e1cda6 --- /dev/null +++ b/src/tx/servicetx.h @@ -0,0 +1,93 @@ +// Copyright (c) 2017 Greg Griffith and the ECC developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SERVICETX_H +#define SERVICETX_H + +#include "uint256.h" +#include "serialize.h" + + +/** The basic transaction that is broadcasted on the network and contained in + * blocks. A transaction can contain multiple inputs and outputs. + */ +class CServiceTransaction +{ +private: + /** Memory only. */ + const uint256 hash; + void UpdateHash() const; + +public: + // Default transaction version. + static const int32_t CURRENT_VERSION=1; + + // Changing the default transaction version requires a two step process: first + // adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date + // bumping the default CURRENT_VERSION at which point both CURRENT_VERSION and + // MAX_STANDARD_VERSION will be equal. + static const int32_t MAX_STANDARD_VERSION=2; + + // The local variables are made const to prevent unintended modification + // without updating the cached hash value. However, CTransaction is not + // actually immutable; deserialization and assignment are implemented, + // and bypass the constness. This is safe, as they update the entire + // structure, including the hash. + int32_t nVersion; + uint16_t nServiceId; + unsigned int nTime; + uint16_t nOpCode; + uint32_t nLockTime; + std::vector vdata; + uint256 paymentReferenceHash; + uint256 securityHash; + + /** Construct a CTransaction that qualifies as IsNull() */ + CServiceTransaction(); + + /** Convert a CTransaction into a CTransaction. */ + CServiceTransaction(const CServiceTransaction &tx); + + CServiceTransaction& operator=(const CServiceTransaction& tx); + + ADD_SERIALIZE_METHODS + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(*const_cast(&this->nVersion)); + nVersion = this->nVersion; + READWRITE(*const_cast(&this->nServiceId)); + READWRITE(*const_cast(&this->nTime)); + READWRITE(*const_cast(&this->nOpCode)); + READWRITE(*const_cast(&nLockTime)); + READWRITE(*const_cast*>(&vdata)); + READWRITE(*const_cast(&this->paymentReferenceHash)); + READWRITE(*const_cast(&this->securityHash)); + if (ser_action.ForRead()) + UpdateHash(); + } + + bool IsNull() const + { + /// op code cannot be 0 if data is empty, this only happens in a null object + return vdata.empty() && nOpCode == 0; + } + + uint256 GetHash() const; + + friend bool operator==(const CServiceTransaction& a, const CServiceTransaction& b) + { + return a.hash == b.hash; + } + + friend bool operator!=(const CServiceTransaction& a, const CServiceTransaction& b) + { + return a.hash != b.hash; + } + std::string ToString() const; + void setSecurityHash(); +}; + + +#endif // SERVICETX_H diff --git a/src/primitives/transaction.cpp b/src/tx/tx.cpp similarity index 72% rename from src/primitives/transaction.cpp rename to src/tx/tx.cpp index 4a1801ba..ec0b11a3 100644 --- a/src/primitives/transaction.cpp +++ b/src/tx/tx.cpp @@ -3,19 +3,22 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "primitives/transaction.h" +#include "tx/tx.h" -#include "hash.h" +#include "crypto/hash.h" #include "tinyformat.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include "txdb.h" #include "timedata.h" -#include "chainparams.h" -#include "chain.h" +#include "networks/networktemplate.h" +#include "chain/chain.h" #include "main.h" #include "args.h" #include "consensus/consensus.h" #include "wallet/wallet.h" +#include "networks/netman.h" +#include "init.h" +#include "txmempool.h" std::string COutPoint::ToString() const { @@ -77,9 +80,11 @@ void CTransaction::UpdateHash() const *const_cast(&hash) = SerializeHash(*this); } -CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), nTime(GetAdjustedTime()), vin(), vout(), nLockTime(0) { } +CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), nTime(GetAdjustedTime()), vin(), vout(), nLockTime(0), serviceReferenceHash() { + serviceReferenceHash.SetNull(); +} -CTransaction::CTransaction(const CTransaction &tx) : nVersion(tx.nVersion), nTime(tx.nTime), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) { +CTransaction::CTransaction(const CTransaction &tx) : nVersion(tx.nVersion), nTime(tx.nTime), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), serviceReferenceHash(tx.serviceReferenceHash) { UpdateHash(); } @@ -90,6 +95,8 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) { *const_cast*>(&vout) = tx.vout; *const_cast(&nLockTime) = tx.nLockTime; *const_cast(&hash) = tx.hash; + *const_cast(&serviceReferenceHash) = tx.serviceReferenceHash; + return *this; } @@ -153,7 +160,7 @@ bool CTransaction::IsFinal(int nBlockHeight, int64_t nBlockTime) const if (nLockTime == 0) return true; if (nBlockHeight == 0) - nBlockHeight = chainActive.Height(); + nBlockHeight = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height(); if (nBlockTime == 0) nBlockTime = GetAdjustedTime(); if ((int64_t)nLockTime < ((int64_t)nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime)) @@ -212,20 +219,20 @@ uint64_t CTransaction::GetCoinAge(uint64_t nCoinAge, bool byValue) const for(const CTxIn& txin: vin) { CDiskTxPos txindex; - if (!pblocktree->ReadTxIndex(txin.prevout.hash, txindex)) + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree->ReadTxIndex(txin.prevout.hash, txindex)) continue; // previous transaction not in main chain // Read block header CBlock block; CDiskBlockPos blockPos(txindex.nFile, txindex.nPos); - if (!ReadBlockFromDisk(block, blockPos, Params().GetConsensus())) + if (!ReadBlockFromDisk(block, blockPos, pnetMan->getActivePaymentNetwork()->GetConsensus())) return false; // unable to read block of previous transaction - if (block.GetBlockTime() + Params().getStakeMinAge() > nTime) + if (block.GetBlockTime() + pnetMan->getActivePaymentNetwork()->getStakeMinAge() > nTime) continue; // only count coins meeting min age requirement CTransaction txPrev; uint256 blockHashOfTx; - if (!GetTransaction(txin.prevout.hash, txPrev, Params().GetConsensus(), blockHashOfTx)) + if (!GetTransaction(txin.prevout.hash, txPrev, pnetMan->getActivePaymentNetwork()->GetConsensus(), blockHashOfTx)) { return false; } @@ -259,20 +266,20 @@ bool CTransaction::GetCoinAge(uint64_t& nCoinAge) const for(const CTxIn& txin: vin) { CDiskTxPos txindex; - if (!pblocktree->ReadTxIndex(txin.prevout.hash, txindex)) + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree->ReadTxIndex(txin.prevout.hash, txindex)) continue; // previous transaction not in main chain // Read block header CBlock block; CDiskBlockPos blockPos(txindex.nFile, txindex.nPos); - if (!ReadBlockFromDisk(block, blockPos, Params().GetConsensus())) + if (!ReadBlockFromDisk(block, blockPos, pnetMan->getActivePaymentNetwork()->GetConsensus())) return false; // unable to read block of previous transaction - if (block.GetBlockTime() + Params().getStakeMinAge() > nTime) + if (block.GetBlockTime() + pnetMan->getActivePaymentNetwork()->getStakeMinAge() > nTime) continue; // only count coins meeting min age requirement CTransaction txPrev; uint256 blockHashOfTx; - if (!GetTransaction(txin.prevout.hash, txPrev, Params().GetConsensus(), blockHashOfTx)) + if (!GetTransaction(txin.prevout.hash, txPrev, pnetMan->getActivePaymentNetwork()->GetConsensus(), blockHashOfTx)) { return false; } @@ -293,3 +300,63 @@ bool CTransaction::GetCoinAge(uint64_t& nCoinAge) const nCoinAge = bnCoinDay.getuint64(); return true; } + + +/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */ +bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow) +{ + CBlockIndex *pindexSlow = NULL; + + LOCK(cs_main); + + if (mempool.lookup(hash, txOut)) + { + return true; + } + + CDiskTxPos postx; + if (pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree->ReadTxIndex(hash, postx)) { + CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); + if (file.IsNull()) + return error("%s: OpenBlockFile failed", __func__); + CBlockHeader header; + try { + file >> header; + fseek(file.Get(), postx.nTxOffset, SEEK_CUR); + file >> txOut; + } catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + hashBlock = header.GetHash(); + if (txOut.GetHash() != hash) + return error("%s: txid mismatch", __func__); + return true; + } + + if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it + int nHeight = -1; + { + CCoinsViewCache &view = *pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip; + const CCoins* coins = view.AccessCoins(hash); + if (coins) + nHeight = coins->nHeight; + } + if (nHeight > 0) + pindexSlow = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive[nHeight]; + } + + if (pindexSlow) { + CBlock block; + if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) { + for (auto const& tx: block.vtx) { + if (tx.GetHash() == hash) { + txOut = tx; + hashBlock = pindexSlow->GetBlockHash(); + return true; + } + } + } + } + + return false; +} diff --git a/src/tx/tx.h b/src/tx/tx.h new file mode 100644 index 00000000..55ac31f8 --- /dev/null +++ b/src/tx/tx.h @@ -0,0 +1,119 @@ +// Copyright (c) 2009-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_PRIMITIVES_TRANSACTION_H +#define BITCOIN_PRIMITIVES_TRANSACTION_H + +#include "txin.h" +#include "txout.h" +#include "consensus/params.h" + +/** The basic transaction that is broadcasted on the network and contained in + * blocks. A transaction can contain multiple inputs and outputs. + */ +class CTransaction +{ +private: + /** Memory only. */ + const uint256 hash; + void UpdateHash() const; + +public: + // Default transaction version. + static const int32_t CURRENT_VERSION=1; + + // Changing the default transaction version requires a two step process: first + // adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date + // bumping the default CURRENT_VERSION at which point both CURRENT_VERSION and + // MAX_STANDARD_VERSION will be equal. + static const int32_t MAX_STANDARD_VERSION=2; + + // The local variables are made const to prevent unintended modification + // without updating the cached hash value. However, CTransaction is not + // actually immutable; deserialization and assignment are implemented, + // and bypass the constness. This is safe, as they update the entire + // structure, including the hash. + int32_t nVersion; + unsigned int nTime; + std::vector vin; + std::vector vout; + uint32_t nLockTime; + uint256 serviceReferenceHash; + + /** Construct a CTransaction that qualifies as IsNull() */ + CTransaction(); + + /** Convert a CTransaction into a CTransaction. */ + CTransaction(const CTransaction &tx); + + CTransaction& operator=(const CTransaction& tx); + + ADD_SERIALIZE_METHODS + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(*const_cast(&this->nVersion)); + nVersion = this->nVersion; + READWRITE(*const_cast(&this->nTime)); + READWRITE(*const_cast*>(&vin)); + READWRITE(*const_cast*>(&vout)); + READWRITE(*const_cast(&nLockTime)); + if (this->nVersion == 2) + { + READWRITE(*const_cast(&this->serviceReferenceHash)); + } + if (ser_action.ForRead()) + UpdateHash(); + } + + bool IsNull() const { + return vin.empty() && vout.empty(); + } + + uint256 GetHash() const; + + // Return sum of txouts. + CAmount GetValueOut() const; + // GetValueIn() is a method on CCoinsViewCache, because + // inputs must be known to compute value in. + + // Compute priority, given priority of inputs and (optionally) tx size + double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const; + + // Compute modified tx size for priority calculation (optionally given tx size) + unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const; + + bool IsCoinBase() const + { + return (vin.size() == 1 && vin[0].prevout.IsNull()); + } + + bool IsCoinStake() const + { + // ppcoin: the coin stake transaction is marked with the first output empty + return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty()); + } + + bool IsFinal(int nBlockHeight=0, int64_t nBlockTime=0) const; + + friend bool operator==(const CTransaction& a, const CTransaction& b) + { + return a.hash == b.hash; + } + + friend bool operator!=(const CTransaction& a, const CTransaction& b) + { + return a.hash != b.hash; + } + std::string ToString() const; + int64_t GetMinFee(unsigned int nBlockSize=1, unsigned int nBytes = 0) const; + bool GetCoinAge(uint64_t& nCoinAge) const; // ppcoin: get transaction coin age + uint64_t GetCoinAge(uint64_t nCoinAge, bool byValue) const; +}; + +/** Retrieve a transaction (from memory pool, or from disk, if possible) */ +bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false); + +#endif // BITCOIN_PRIMITIVES_TRANSACTION_H diff --git a/src/tx/txin.cpp b/src/tx/txin.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/tx/txin.h b/src/tx/txin.h new file mode 100644 index 00000000..979f14ce --- /dev/null +++ b/src/tx/txin.h @@ -0,0 +1,83 @@ +#ifndef TXIN_H +#define TXIN_H + +#include "outpoint.h" +#include "script/script.h" + +/** An input of a transaction. It contains the location of the previous + * transaction's output that it claims and a signature that matches the + * output's public key. + */ +class CTxIn +{ +public: + COutPoint prevout; + CScript scriptSig; + uint32_t nSequence; + + /* Setting nSequence to this value for every input in a transaction + * disables nLockTime. */ + static const uint32_t SEQUENCE_FINAL = 0xffffffff; + + /* Below flags apply in the context of BIP 68*/ + /* If this flag set, CTxIn::nSequence is NOT interpreted as a + * relative lock-time. */ + static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31); + + /* If CTxIn::nSequence encodes a relative lock-time and this flag + * is set, the relative lock-time has units of 512 seconds, + * otherwise it specifies blocks with a granularity of 1. */ + static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22); + + /* If CTxIn::nSequence encodes a relative lock-time, this mask is + * applied to extract that lock-time from the sequence field. */ + static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff; + + /* In order to use the same number of bits to encode roughly the + * same wall-clock duration, and because blocks are naturally + * limited to occur every 600s on average, the minimum granularity + * for time-based relative lock-time is fixed at 512 seconds. + * Converting from CTxIn::nSequence to seconds is performed by + * multiplying by 512 = 2^9, or equivalently shifting up by + * 9 bits. */ + static const int SEQUENCE_LOCKTIME_GRANULARITY = 9; + + CTxIn() + { + nSequence = SEQUENCE_FINAL; + } + + explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL); + CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL); + + ADD_SERIALIZE_METHODS + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(prevout); + READWRITE(*(CScriptBase*)(&scriptSig)); + READWRITE(nSequence); + } + + friend bool operator==(const CTxIn& a, const CTxIn& b) + { + return (a.prevout == b.prevout && + a.scriptSig == b.scriptSig && + a.nSequence == b.nSequence); + } + + friend bool operator!=(const CTxIn& a, const CTxIn& b) + { + return !(a == b); + } + + bool IsFinal() const + { + return (nSequence == std::numeric_limits::max()); + } + + + std::string ToString() const; +}; + +#endif // TXIN_H diff --git a/src/tx/txout.cpp b/src/tx/txout.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/tx/txout.h b/src/tx/txout.h new file mode 100644 index 00000000..bb8318ac --- /dev/null +++ b/src/tx/txout.h @@ -0,0 +1,93 @@ +#ifndef TXOUT_H +#define TXOUT_H + +#include "amount.h" +#include "script/script.h" + +/** An output of a transaction. It contains the public key that the next input + * must be able to sign with to claim it. + */ +class CTxOut +{ +public: + CAmount nValue; + CScript scriptPubKey; + + CTxOut() + { + SetNull(); + } + + CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn); + + ADD_SERIALIZE_METHODS + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(nValue); + READWRITE(*(CScriptBase*)(&scriptPubKey)); + } + + void SetNull() + { + nValue = -1; + scriptPubKey.clear(); + } + + bool IsNull() const + { + return (nValue == -1); + } + + void SetEmpty() + { + nValue = 0; + scriptPubKey.clear(); + } + + bool IsEmpty() const + { + return (nValue == 0 && scriptPubKey.empty()); + } + + uint256 GetHash() const; + + CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const + { + // "Dust" is defined in terms of CTransaction::minRelayTxFee, + // which has units satoshis-per-kilobyte. + // If you'd pay more than 1/3 in fees + // to spend something, then we consider it dust. + // A typical spendable txout is 34 bytes big, and will + // need a CTxIn of at least 148 bytes to spend: + // so dust is a spendable txout less than + // 546*minRelayTxFee/1000 (in satoshis) + if (scriptPubKey.IsUnspendable()) + return 0; + + size_t nSize = GetSerializeSize(*this, SER_DISK, 0); + // the 148 mentioned above + nSize += (32 + 4 + 1 + 107 + 4); + return 3*minRelayTxFee.GetFee(nSize); + } + + bool IsDust(const CFeeRate &minRelayTxFee) const + { + return (nValue < GetDustThreshold(minRelayTxFee)); + } + + friend bool operator==(const CTxOut& a, const CTxOut& b) + { + return (a.nValue == b.nValue && + a.scriptPubKey == b.scriptPubKey); + } + + friend bool operator!=(const CTxOut& a, const CTxOut& b) + { + return !(a == b); + } + + std::string ToString() const; +}; + +#endif // TXOUT_H diff --git a/src/txdb.cpp b/src/txdb.cpp index baef9175..139f268c 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -5,10 +5,12 @@ #include "txdb.h" -#include "chain.h" -#include "chainparams.h" -#include "hash.h" +#include "coins.h" +#include "chain/chain.h" +#include "networks/networktemplate.h" +#include "crypto/hash.h" #include "main.h" +#include "init.h" #include "pow.h" #include "uint256.h" @@ -16,6 +18,7 @@ #include +static const char DB_COIN = 'C'; static const char DB_COINS = 'c'; static const char DB_BLOCK_FILES = 'f'; static const char DB_TXINDEX = 't'; @@ -26,6 +29,28 @@ static const char DB_FLAG = 'F'; static const char DB_REINDEX_FLAG = 'R'; static const char DB_LAST_BLOCK = 'l'; +namespace { + +struct CoinEntry { + COutPoint *outpoint; + char key; + CoinEntry(const COutPoint *ptr) + : outpoint(const_cast(ptr)), key(DB_COIN) {} + + template void Serialize(Stream &s) const { + s << key; + s << outpoint->hash; + s << VARINT(outpoint->n); + } + + template void Unserialize(Stream &s) { + s >> key; + s >> outpoint->hash; + s >> VARINT(outpoint->n); + } +}; +} + CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe, true) { @@ -47,7 +72,7 @@ uint256 CCoinsViewDB::GetBestBlock() const { } bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { - CDBBatch batch(&db.GetObfuscateKey()); + CDBBatch batch(db); size_t count = 0; size_t changed = 0; for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { @@ -131,7 +156,7 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { } { LOCK(cs_main); - stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight; + stats.nHeight = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(stats.hashBlock)->second->nHeight; } stats.hashSerialized = ss.GetHash(); stats.nTotalAmount = nTotalAmount; @@ -139,23 +164,32 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { } bool CBlockTreeDB::WriteBatchSync(const std::vector >& fileInfo, int nLastFile, const std::vector& blockinfo) { - CDBBatch batch(&GetObfuscateKey()); - for (std::vector >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) { + CDBBatch batch(*this); + for (std::vector >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) + { batch.Write(std::make_pair(DB_BLOCK_FILES, it->first), *it->second); } batch.Write(DB_LAST_BLOCK, nLastFile); - for (std::vector::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) { + for (std::vector::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) + { batch.Write(std::make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it)); } return WriteBatch(batch, true); } +bool CBlockTreeDB::EraseBlockIndex(uint256 hashToDelete) +{ + CDBBatch batch(*this); + batch.Erase(std::make_pair(DB_BLOCK_INDEX, hashToDelete)); + return WriteBatch(batch); +} + bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) { return Read(std::make_pair(DB_TXINDEX, txid), pos); } bool CBlockTreeDB::WriteTxIndex(const std::vector >&vect) { - CDBBatch batch(&GetObfuscateKey()); + CDBBatch batch(*this); for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) batch.Write(std::make_pair(DB_TXINDEX, it->first), it->second); return WriteBatch(batch); @@ -187,8 +221,8 @@ bool CBlockTreeDB::LoadBlockIndexGuts() CDiskBlockIndex diskindex; if (pcursor->GetValue(diskindex)) { // Construct block index object - CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); - pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); + CBlockIndex* pindexNew = pnetMan->getActivePaymentNetwork()->getChainManager()->InsertBlockIndex(diskindex.GetBlockHash()); + pindexNew->pprev = pnetMan->getActivePaymentNetwork()->getChainManager()->InsertBlockIndex(diskindex.hashPrev); pindexNew->nHeight = diskindex.nHeight; pindexNew->nFile = diskindex.nFile; pindexNew->nDataPos = diskindex.nDataPos; @@ -207,17 +241,6 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->prevoutStake = diskindex.prevoutStake; pindexNew->nStakeTime = diskindex.nStakeTime; pindexNew->hashProofOfStake = diskindex.hashProofOfStake; - - /// TODO: fix the root cause of this problem. it is fine for now since PoW has been off for the last million+ blocks - /// but the root issue should be adjusted - /* - if(pindexNew->IsProofOfWork()) - { - if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) - return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); - } - */ - pcursor->Next(); } else { return error("LoadBlockIndex() : failed to read value"); @@ -229,3 +252,55 @@ bool CBlockTreeDB::LoadBlockIndexGuts() return true; } + +/** Upgrade the database from older formats. + * + * Currently implemented: from the per-tx utxo model (0.8..0.14.x) to per-txout. + */ +bool CCoinsViewDB::Upgrade() +{ + std::unique_ptr pcursor(db.NewIterator()); + pcursor->Seek(std::make_pair(DB_COINS, uint256())); + if (!pcursor->Valid()) { + return true; + } + + LogPrintf("Upgrading database...\n"); + size_t batch_size = 1 << 24; + CDBBatch batch(db); + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + if (!pcursor->GetKey(key) || key.first != DB_COINS) { + break; + } + + CCoins old_coins; + if (!pcursor->GetValue(old_coins)) { + return error("%s: cannot parse CCoins record", __func__); + } + + COutPoint outpoint(key.second, 0); + for (size_t i = 0; i < old_coins.vout.size(); ++i) { + if (!old_coins.vout[i].IsNull() && + !old_coins.vout[i].scriptPubKey.IsUnspendable()) { + Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, + old_coins.fCoinBase); + outpoint.n = i; + CoinEntry entry(&outpoint); + batch.Write(entry, newcoin); + } + } + + batch.Erase(key); + if (batch.SizeEstimate() > batch_size) { + db.WriteBatch(batch); + batch.Clear(); + } + + pcursor->Next(); + } + + db.WriteBatch(batch); + return true; + } diff --git a/src/txdb.h b/src/txdb.h index 22e0c570..2156d905 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -39,6 +39,9 @@ class CCoinsViewDB : public CCoinsView uint256 GetBestBlock() const; bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); bool GetStats(CCoinsStats &stats) const; + + //! Attempt to update from an older database format. Returns whether an error occurred. + bool Upgrade(); }; /** Access to the block database (blocks/index/) */ @@ -60,6 +63,7 @@ class CBlockTreeDB : public CDBWrapper bool WriteFlag(const std::string &name, bool fValue); bool ReadFlag(const std::string &name, bool &fValue); bool LoadBlockIndexGuts(); + bool EraseBlockIndex(uint256 hashToDelete); }; #endif // BITCOIN_TXDB_H diff --git a/src/txmempool.cpp b/src/txmempool.cpp index b563d34a..53a06a58 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -12,9 +12,9 @@ #include "policy/fees.h" #include "streams.h" #include "timedata.h" -#include "util.h" -#include "utilmoneystr.h" -#include "utiltime.h" +#include "util/util.h" +#include "util/utilmoneystr.h" +#include "util/utiltime.h" #include "version.h" #include diff --git a/src/txmempool.h b/src/txmempool.h index 5997346b..9888e879 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -11,7 +11,7 @@ #include "amount.h" #include "coins.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include "sync.h" #undef foreach @@ -201,7 +201,7 @@ struct mempoolentry_txid class CompareTxMemPoolEntryByDescendantScore { public: - bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) + bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const { bool fUseADescendants = UseDescendantScore(a); bool fUseBDescendants = UseDescendantScore(b); @@ -223,7 +223,7 @@ class CompareTxMemPoolEntryByDescendantScore } // Calculate which score to use for an entry (avoiding division). - bool UseDescendantScore(const CTxMemPoolEntry &a) + bool UseDescendantScore(const CTxMemPoolEntry &a) const { double f1 = (double)a.GetModifiedFee() * a.GetSizeWithDescendants(); double f2 = (double)a.GetModFeesWithDescendants() * a.GetTxSize(); @@ -238,7 +238,7 @@ class CompareTxMemPoolEntryByDescendantScore class CompareTxMemPoolEntryByScore { public: - bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) + bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const { double f1 = (double)a.GetModifiedFee() * b.GetTxSize(); double f2 = (double)b.GetModifiedFee() * a.GetTxSize(); @@ -252,7 +252,7 @@ class CompareTxMemPoolEntryByScore class CompareTxMemPoolEntryByEntryTime { public: - bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) + bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const { return a.GetTime() < b.GetTime(); } diff --git a/src/uint256.cpp b/src/uint256.cpp index c58c88bf..3b532a1e 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -5,7 +5,7 @@ #include "uint256.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include #include diff --git a/src/uint256.h b/src/uint256.h index 6b54e9b1..b91fe1c6 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -87,13 +87,13 @@ class base_blob } template - void Serialize(Stream& s, int nType, int nVersion) const + void Serialize(Stream& s) const { s.write((char*)data, sizeof(data)); } template - void Unserialize(Stream& s, int nType, int nVersion) + void Unserialize(Stream& s) { s.read((char*)data, sizeof(data)); } diff --git a/src/undo.h b/src/undo.h index 5955dabb..b898c378 100644 --- a/src/undo.h +++ b/src/undo.h @@ -7,7 +7,7 @@ #define BITCOIN_UNDO_H #include "compressor.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include "serialize.h" /** Undo information for a CTxIn @@ -34,22 +34,22 @@ class CTxInUndo } template - void Serialize(Stream &s, int nType, int nVersion) const { - ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion); + void Serialize(Stream &s) const { + ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0))); if (nHeight > 0) - ::Serialize(s, VARINT(this->nVersion), nType, nVersion); - ::Serialize(s, CTxOutCompressor(REF(txout)), nType, nVersion); + ::Serialize(s, VARINT(this->nVersion)); + ::Serialize(s, CTxOutCompressor(REF(txout))); } template - void Unserialize(Stream &s, int nType, int nVersion) { + void Unserialize(Stream &s) { unsigned int nCode = 0; - ::Unserialize(s, VARINT(nCode), nType, nVersion); + ::Unserialize(s, VARINT(nCode)); nHeight = nCode / 2; fCoinBase = nCode & 1; if (nHeight > 0) - ::Unserialize(s, VARINT(this->nVersion), nType, nVersion); - ::Unserialize(s, REF(CTxOutCompressor(REF(txout))), nType, nVersion); + ::Unserialize(s, VARINT(this->nVersion)); + ::Unserialize(s, REF(CTxOutCompressor(REF(txout)))); } }; @@ -63,7 +63,7 @@ class CTxUndo ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(vprevout); } }; @@ -77,9 +77,18 @@ class CBlockUndo ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(vtxundo); } }; +enum DisconnectResult { + // All good. + DISCONNECT_OK, + // Rolled back, but UTXO set was inconsistent with block. + DISCONNECT_UNCLEAN, + // Something else went wrong. + DISCONNECT_FAILED, +}; + #endif // BITCOIN_UNDO_H diff --git a/src/util.cpp b/src/util/util.cpp similarity index 98% rename from src/util.cpp rename to src/util/util.cpp index 1b730833..9a1fa568 100644 --- a/src/util.cpp +++ b/src/util/util.cpp @@ -3,19 +3,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - -#include "util.h" +#include "util/util.h" #include "args.h" -#include "chainparamsbase.h" +#include "networks/netman.h" +#include "init.h" #include "random.h" #include "serialize.h" #include "sync.h" -#include "utilstrencodings.h" -#include "utiltime.h" +#include "util/utilstrencodings.h" +#include "util/utiltime.h" #include @@ -413,17 +410,23 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) if (!path.empty()) return path; - if (gArgs.IsArgSet("-datadir")) { + if (gArgs.IsArgSet("-datadir")) + { path = fs::system_complete(gArgs.GetArg("-datadir", "")); - if (!fs::is_directory(path)) { + if (!fs::is_directory(path)) + { path = ""; return path; } - } else { + } + else + { path = GetDefaultDataDir(); } if (fNetSpecific) - path /= BaseParams().DataDir(); + { + path /= pnetMan->getActivePaymentNetwork()->DataDir(); + } fs::create_directories(path); @@ -585,7 +588,7 @@ void ShrinkDebugFile() // Scroll debug.log if it's getting too big boost::filesystem::path pathLog = GetDataDir() / "debug.log"; FILE* file = fopen(pathLog.string().c_str(), "r"); - if (file && boost::filesystem::file_size(pathLog) > 10 * 1000000) + if (file && boost::filesystem::file_size(pathLog) > 20000) { // Restart the file with some of the end std::vector vch(200000,0); diff --git a/src/util.h b/src/util/util.h similarity index 98% rename from src/util.h rename to src/util/util.h index 05b157e6..39849be9 100644 --- a/src/util.h +++ b/src/util/util.h @@ -10,13 +10,9 @@ #ifndef BITCOIN_UTIL_H #define BITCOIN_UTIL_H -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - #include "compat.h" #include "tinyformat.h" -#include "utiltime.h" +#include "util/utiltime.h" #include #include diff --git a/src/utilmoneystr.cpp b/src/util/utilmoneystr.cpp similarity index 95% rename from src/utilmoneystr.cpp rename to src/util/utilmoneystr.cpp index 6e6e3318..dda3e0ef 100644 --- a/src/utilmoneystr.cpp +++ b/src/util/utilmoneystr.cpp @@ -3,11 +3,11 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "utilmoneystr.h" +#include "util/utilmoneystr.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include "tinyformat.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" std::string FormatMoney(const CAmount& n) { diff --git a/src/utilmoneystr.h b/src/util/utilmoneystr.h similarity index 100% rename from src/utilmoneystr.h rename to src/util/utilmoneystr.h diff --git a/src/utilstrencodings.cpp b/src/util/utilstrencodings.cpp similarity index 99% rename from src/utilstrencodings.cpp rename to src/util/utilstrencodings.cpp index 0c6b304a..1d34b7cc 100644 --- a/src/utilstrencodings.cpp +++ b/src/util/utilstrencodings.cpp @@ -3,7 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include "tinyformat.h" diff --git a/src/utilstrencodings.h b/src/util/utilstrencodings.h similarity index 100% rename from src/utilstrencodings.h rename to src/util/utilstrencodings.h diff --git a/src/utiltime.cpp b/src/util/utiltime.cpp similarity index 94% rename from src/utiltime.cpp rename to src/util/utiltime.cpp index 4adfd30b..70a73fcc 100644 --- a/src/utiltime.cpp +++ b/src/util/utiltime.cpp @@ -3,11 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - -#include "utiltime.h" +#include "util/utiltime.h" #include #include diff --git a/src/utiltime.h b/src/util/utiltime.h similarity index 100% rename from src/utiltime.h rename to src/util/utiltime.h diff --git a/src/verifydb.cpp b/src/verifydb.cpp new file mode 100644 index 00000000..284ed629 --- /dev/null +++ b/src/verifydb.cpp @@ -0,0 +1,95 @@ +#include + +#include "verifydb.h" +#include "main.h" +#include "init.h" +#include "processblock.h" + + +CVerifyDB::CVerifyDB() +{ + uiInterface.ShowProgress(_("Verifying blocks..."), 0); +} + +CVerifyDB::~CVerifyDB() +{ + uiInterface.ShowProgress("", 100); +} + +bool CVerifyDB::VerifyDB(const CNetworkTemplate& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) +{ + LOCK(cs_main); + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip() == NULL || pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->pprev == NULL) + return true; + + // Verify blocks in the best chain + if (nCheckDepth <= 0) + nCheckDepth = 1000000000; // suffices until the year 19000 + if (nCheckDepth > pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height()) + nCheckDepth = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height(); + nCheckLevel = std::max(0, std::min(4, nCheckLevel)); + LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); + CCoinsViewCache coins(coinsview); + CBlockIndex* pindexState = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); + CBlockIndex* pindexFailure = NULL; + int nGoodTransactions = 0; + CValidationState state; + for (CBlockIndex* pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) + { + boost::this_thread::interruption_point(); + uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))))); + if (pindex->nHeight < pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height()-nCheckDepth) + break; + CBlock block; + // check level 0: read from disk + if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) + return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); + // check level 1: verify block validity + if (nCheckLevel >= 1 && !CheckBlock(block, state)) + return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); + // check level 2: verify undo validity + if (nCheckLevel >= 2 && pindex) { + CBlockUndo undo; + CDiskBlockPos pos = pindex->GetUndoPos(); + if (!pos.IsNull()) { + if (!UndoReadFromDisk(undo, pos, pindex->pprev->GetBlockHash())) + return error("VerifyDB(): *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); + } + } + // check level 3: check for inconsistencies during memory-only disconnect of tip blocks + if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pnetMan->getActivePaymentNetwork()->getChainManager()->pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) { + bool fClean = true; + if (!DisconnectBlock(block, state, pindex, coins, &fClean)) + return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); + pindexState = pindex->pprev; + if (!fClean) { + nGoodTransactions = 0; + pindexFailure = pindex; + } else + nGoodTransactions += block.vtx.size(); + } + if (ShutdownRequested()) + return true; + } + if (pindexFailure) + return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions); + + // check level 4: try reconnecting blocks + if (nCheckLevel >= 4) { + CBlockIndex *pindex = pindexState; + while (pindex != pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()) { + boost::this_thread::interruption_point(); + uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)))); + pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Next(pindex); + CBlock block; + if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) + return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); + if (!ConnectBlock(block, state, pindex, coins)) + return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); + } + } + + LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindexState->nHeight, nGoodTransactions); + + return true; +} diff --git a/src/verifydb.h b/src/verifydb.h new file mode 100644 index 00000000..48e59255 --- /dev/null +++ b/src/verifydb.h @@ -0,0 +1,15 @@ +#ifndef VERIFYDB_H +#define VERIFYDB_H + +#include "networks/networktemplate.h" +#include "coins.h" + +/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */ +class CVerifyDB { +public: + CVerifyDB(); + ~CVerifyDB(); + bool VerifyDB(const CNetworkTemplate& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth); +}; + +#endif // VERIFYDB_H diff --git a/src/versionbits.h b/src/versionbits.h index 04f47382..37377d96 100644 --- a/src/versionbits.h +++ b/src/versionbits.h @@ -5,7 +5,7 @@ #ifndef BITCOIN_CONSENSUS_VERSIONBITS #define BITCOIN_CONSENSUS_VERSIONBITS -#include "chain.h" +#include "chain/chain.h" #include /** What block version to use for new blocks (pre versionbits) */ diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index e51f3961..653034e2 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -6,7 +6,7 @@ #include "script/script.h" #include "script/standard.h" -#include "util.h" +#include "util/util.h" #include #include diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index ff0143a9..0f1a8fa3 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -46,7 +46,7 @@ class CMasterKey ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(vchCryptedKey); READWRITE(vchSalt); READWRITE(nDerivationMethod); diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 26d814ff..a9e85722 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -6,11 +6,11 @@ #include "db.h" #include "addrman.h" -#include "hash.h" +#include "crypto/hash.h" #include "protocol.h" -#include "util.h" +#include "util/util.h" #include "args.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8a465ff9..57b410bc 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -6,28 +6,28 @@ #include "wallet/wallet.h" #include "base58.h" -#include "checkpoints.h" -#include "chain.h" +#include "chain/checkpoints.h" +#include "chain/chain.h" #include "coincontrol.h" #include "coins.h" #include "consensus/consensus.h" #include "consensus/validation.h" +#include "init.h" #include "kernel.h" #include "key.h" #include "keystore.h" #include "main.h" #include "net.h" #include "policy/policy.h" -#include "primitives/block.h" -#include "primitives/transaction.h" +#include "tx/tx.h" #include "script/script.h" #include "script/sign.h" #include "timedata.h" #include "txdb.h" #include "txmempool.h" -#include "util.h" +#include "util/util.h" #include "args.h" -#include "utilmoneystr.h" +#include "util/utilmoneystr.h" #include @@ -299,13 +299,6 @@ void CWallet::SetBestChain(const CBlockLocator& loc) walletdb.WriteBestBlock(loc); } -void CWallet::ForceSetMinVersion(int nVersion) -{ - CWalletDB* pwalletdbIn = NULL; - CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);; - pwalletdb->WriteMinVersion(nVersion); -} - bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit) { LOCK(cs_wallet); // nWalletVersion @@ -654,7 +647,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD wtx.nTimeSmart = wtx.nTimeReceived; if (!wtxIn.hashUnset()) { - if (mapBlockIndex.count(wtxIn.hashBlock)) + if (pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(wtxIn.hashBlock)) { int64_t latestNow = wtx.nTimeReceived; int64_t latestEntry = 0; @@ -687,7 +680,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD } } - int64_t blocktime = mapBlockIndex[wtxIn.hashBlock]->GetBlockTime(); + int64_t blocktime = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[wtxIn.hashBlock]->GetBlockTime(); wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow)); } else @@ -858,10 +851,10 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) LOCK2(cs_main, cs_wallet); int conflictconfirms = 0; - if (mapBlockIndex.count(hashBlock)) { - CBlockIndex* pindex = mapBlockIndex[hashBlock]; - if (chainActive.Contains(pindex)) { - conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1); + if (pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.count(hashBlock)) { + CBlockIndex* pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex[hashBlock]; + if (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(pindex)) { + conflictconfirms = -(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindex->nHeight + 1); } } // If number of conflict confirms cannot be determined, this means @@ -1116,6 +1109,11 @@ void CWalletTx::GetAmounts(std::list& listReceived, for (unsigned int i = 0; i < vout.size(); ++i) { const CTxOut& txout = vout[i]; + + // Skip stake out for coinstake transactions + if (txout.scriptPubKey.empty()) + continue; + isminetype fIsMine = pwallet->IsMine(txout); // Only need to handle txouts if AT LEAST one of these is true: // 1) they debit from us (sent) @@ -1202,7 +1200,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) { int ret = 0; int64_t nNow = GetTime(); - const CChainParams& chainParams = Params(); + const CNetworkTemplate& chainParams = pnetMan->getActivePaymentNetwork(); CBlockIndex* pindex = pindexStart; { @@ -1211,24 +1209,24 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) // no need to read and scan block, if block was created before // our wallet birthday (as adjusted for block time variability) while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200))) - pindex = chainActive.Next(pindex); + pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Next(pindex); ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup double dProgressStart = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false); - double dProgressTip = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip(), false); + double dProgressTip = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(), false); while (pindex) { if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); CBlock block; - ReadBlockFromDisk(block, pindex, Params().GetConsensus()); + ReadBlockFromDisk(block, pindex, pnetMan->getActivePaymentNetwork()->GetConsensus()); for (auto& tx: block.vtx) { if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) ret++; } - pindex = chainActive.Next(pindex); + pindex = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Next(pindex); if (GetTime() >= nNow + 60) { nNow = GetTime(); LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex)); @@ -1753,6 +1751,32 @@ static void ApproximateBestSubset(std::vector::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + const CWalletTx* pcoin = &(*it).second; + if (pcoin->IsCoinStake() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) + nTotal += CWallet::GetCredit(*pcoin, ISMINE_ALL); + } + return nTotal; +} + +CAmount CWallet::GetNewMint() const +{ + CAmount nTotal = 0; + LOCK(cs_wallet); + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + const CWalletTx* pcoin = &(*it).second; + if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) + nTotal += CWallet::GetCredit(*pcoin, ISMINE_ALL); + } + return nTotal; +} + bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet) const { @@ -2013,7 +2037,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT // enough, that fee sniping isn't a problem yet, but by implementing a fix // now we ensure code won't be written that makes assumptions about // nLockTime that preclude a fix later. - txNew.nLockTime = chainActive.Height(); + txNew.nLockTime = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height(); // Secondly occasionally randomly pick a nLockTime even further back, so // that transactions that are delayed after signing for whatever reason, @@ -2022,7 +2046,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT if (GetRandInt(10) == 0) txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100)); - assert(txNew.nLockTime <= (unsigned int)chainActive.Height()); + assert(txNew.nLockTime <= (unsigned int)(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height())); assert(txNew.nLockTime < LOCKTIME_THRESHOLD); { @@ -2106,8 +2130,39 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT // coin control: send change to custom address if (coinControl && !boost::get(&coinControl->destChange)) + { scriptChange = GetScriptForDestination(coinControl->destChange); - + } + else if(gArgs.GetBoolArg("-returnchange", DEFAULT_RETURN_CHANGE)) + { + std::map balances = GetAddressBalances(); + if(balances.size() < 1) + { + /// if we are in here, something went wrong with getting the address balance map so we should default to generating a new key + /// this is the same behavior if -returnchange was false + CPubKey vchPubKey; + bool ret; + ret = reservekey.GetReservedKey(vchPubKey); + assert(ret); // should never fail, as we just unlocked + + scriptChange = GetScriptForDestination(vchPubKey.GetID()); + } + else + { + CTxDestination highestAddr; + CAmount highestValue = 0; + highestAddr = balances.begin()->first; //make sure it is always at least an address, this is just a saftey + for(std::map::iterator it = balances.begin(); it != balances.end(); ++it) + { + if(it->second > highestValue) + { + highestValue = it->second; + highestAddr = it->first; + } + } + scriptChange = GetScriptForDestination(highestAddr); + } + } // no coin control: send change to newly generated address else { @@ -2893,7 +2948,7 @@ void CWallet::GetKeyBirthTimes(std::map &mapKeyBirth) const { mapKeyBirth[it->first] = it->second.nCreateTime; // map in which we'll infer heights of other keys - CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganised; use a 144-block safety margin + CBlockIndex *pindexMax = pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive[std::max(0, pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - 144)]; // the tip can be reorganised; use a 144-block safety margin std::map mapKeyFirstBlock; std::set setKeys; GetKeys(setKeys); @@ -2912,8 +2967,8 @@ void CWallet::GetKeyBirthTimes(std::map &mapKeyBirth) const { for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) { // iterate over all wallet transactions... const CWalletTx &wtx = (*it).second; - BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock); - if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) { + BlockMap::const_iterator blit = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(wtx.hashBlock); + if (blit != pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end() && pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(blit->second)) { // ... which are already in a block int nHeight = blit->second->nHeight; for (auto const& txout: wtx.vout) { @@ -3014,14 +3069,14 @@ int CMerkleTx::SetMerkleBranch(const CBlock& block) } // Is the tx in a block that's in the main chain - BlockMap::iterator mi = mapBlockIndex.find(hashBlock); - if (mi == mapBlockIndex.end()) + BlockMap::iterator mi = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(hashBlock); + if (mi == pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) return 0; const CBlockIndex* pindex = (*mi).second; - if (!pindex || !chainActive.Contains(pindex)) + if (!pindex || !pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(pindex)) return 0; - return chainActive.Height() - pindex->nHeight + 1; + return pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindex->nHeight + 1; } int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const @@ -3032,15 +3087,15 @@ int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const AssertLockHeld(cs_main); // Find the block it claims to be in - BlockMap::iterator mi = mapBlockIndex.find(hashBlock); - if (mi == mapBlockIndex.end()) + BlockMap::iterator mi = pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.find(hashBlock); + if (mi == pnetMan->getActivePaymentNetwork()->getChainManager()->mapBlockIndex.end()) return 0; CBlockIndex* pindex = (*mi).second; - if (!pindex || !chainActive.Contains(pindex)) + if (!pindex || !pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Contains(pindex)) return 0; pindexRet = pindex; - return ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1); + return ((nIndex == -1) ? (-1) : 1) * (pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Height() - pindex->nHeight + 1); } int CMerkleTx::GetBlocksToMaturity() const @@ -3195,7 +3250,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int // The following split & combine thresholds are important to security // Should not be adjusted if you don't understand the consequences static unsigned int nStakeSplitAge = (60 * 60 * 24 * 30); - const CBlockIndex* pIndex0 = GetLastBlockIndex(chainActive.Tip(), false); + const CBlockIndex* pIndex0 = GetLastBlockIndex(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(), false); int64_t nCombineThreshold = 0; if(pIndex0->pprev) nCombineThreshold = GetProofOfWorkReward(pIndex0->nHeight, DEFAULT_TRANSACTION_MINFEE , pIndex0->pprev->GetBlockHash()) / 3; @@ -3234,7 +3289,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int CDiskTxPos txindex; { LOCK2(cs_main, cs_wallet); - if (!pblocktree->ReadTxIndex(pcoin.first->GetHash(), txindex)) + if (!pnetMan->getActivePaymentNetwork()->getChainManager()->pblocktree->ReadTxIndex(pcoin.first->GetHash(), txindex)) continue; } @@ -3243,14 +3298,14 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int { LOCK2(cs_main, cs_wallet); CDiskBlockPos blockPos(txindex.nFile, txindex.nPos); - if (!ReadBlockFromDisk(block, blockPos, Params().GetConsensus())) + if (!ReadBlockFromDisk(block, blockPos, pnetMan->getActivePaymentNetwork()->GetConsensus())) continue; } static int nMaxStakeSearchInterval = 60; // LogPrintf(">> block.GetBlockTime() = %"PRI64d", nStakeMinAge = %d, txNew.nTime = %d\n", block.GetBlockTime(), nStakeMinAge,txNew.nTime); - if (block.GetBlockTime() + Params().getStakeMinAge() > txNew.nTime - nMaxStakeSearchInterval) + if (block.GetBlockTime() + pnetMan->getActivePaymentNetwork()->getStakeMinAge() > txNew.nTime - nMaxStakeSearchInterval) continue; // only count coins meeting min age requirement { @@ -3260,7 +3315,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int uint256 hashProofOfStake; hashProofOfStake.SetNull(); COutPoint prevoutStake = COutPoint(pcoin.first->GetHash(), pcoin.second); - if (CheckStakeKernelHash(chainActive.Tip()->nHeight+1, block, txindex.nTxOffset, *pcoin.first, prevoutStake, txNew.nTime, hashProofOfStake)) + if (CheckStakeKernelHash(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip()->nHeight+1, block, txindex.nTxOffset, *pcoin.first, prevoutStake, txNew.nTime, hashProofOfStake)) { // Found a kernel if (fDebug) @@ -3352,7 +3407,9 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int if (pcoin.first->vout[pcoin.second].nValue > nCombineThreshold) continue; // Do not add input that is still too young - if (pcoin.first->nTime + Params().getStakeMaxAge() > txNew.nTime) + /// using stake max age here isnt a bug, its a feature i swear + /// TODO fix that - 2017/10/29 + if (pcoin.first->nTime + pnetMan->getActivePaymentNetwork()->getStakeMaxAge() > txNew.nTime) continue; txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second)); nCredit += pcoin.first->vout[pcoin.second].nValue; @@ -3362,7 +3419,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int // Calculate coin age reward { uint64_t nCoinAge; - const CBlockIndex* pIndex0 = GetLastBlockIndex(chainActive.Tip(), false); + const CBlockIndex* pIndex0 = GetLastBlockIndex(pnetMan->getActivePaymentNetwork()->getChainManager()->chainActive.Tip(), false); if (!txNew.GetCoinAge(nCoinAge)) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 761c2dae..be3a4430 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -10,7 +10,7 @@ #include "streams.h" #include "tinyformat.h" #include "ui_interface.h" -#include "utilstrencodings.h" +#include "util/utilstrencodings.h" #include "validationinterface.h" #include "wallet/crypter.h" #include "wallet/wallet_ismine.h" @@ -74,12 +74,12 @@ class CWalletTx; /** (client) version numbers for particular wallet features */ enum WalletFeature { - FEATURE_BASE = 1050, // the earliest version new wallets supports (only useful for getinfo's clientversion output) + FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getinfo's clientversion output) - FEATURE_WALLETCRYPT = 4000, // wallet encryption - FEATURE_COMPRPUBKEY = 6000, // compressed public keys + FEATURE_WALLETCRYPT = 40000, // wallet encryption + FEATURE_COMPRPUBKEY = 60000, // compressed public keys - FEATURE_LATEST = 6000 + FEATURE_LATEST = 60000 }; @@ -96,8 +96,9 @@ class CKeyPool ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); READWRITE(nTime); READWRITE(vchPubKey); @@ -191,7 +192,7 @@ class CMerkleTx : public CTransaction ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { std::vector vMerkleBranch; // For compatibility with older versions. READWRITE(*(CTransaction*)this); nVersion = this->nVersion; @@ -311,7 +312,7 @@ class CWalletTx : public CMerkleTx ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { if (ser_action.ForRead()) Init(NULL); char fSpent = false; @@ -445,8 +446,9 @@ class CWalletKey ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); READWRITE(vchPrivKey); READWRITE(nTimeCreated); @@ -658,10 +660,13 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount GetBalance() const; CAmount GetUnconfirmedBalance() const; CAmount GetImmatureBalance() const; + CAmount GetStake() const; + CAmount GetNewMint() const; CAmount GetWatchOnlyBalance() const; CAmount GetUnconfirmedWatchOnlyBalance() const; CAmount GetImmatureWatchOnlyBalance() const; + /** * Insert additional inputs into the transaction by * calling CreateTransaction(); @@ -754,7 +759,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool SetDefaultKey(const CPubKey &vchPubKey); //! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower - void ForceSetMinVersion(int nVersion); bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = NULL, bool fExplicit = false); //! change which version we're allowed to upgrade to (note that this does not immediately imply upgrading to that format) @@ -853,8 +857,9 @@ class CAccount ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); READWRITE(vchPubKey); } @@ -897,8 +902,9 @@ class CAccountingEntry ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); //! Note: strAccount is serialized as part of the key, not here. READWRITE(nCreditDebit); @@ -911,7 +917,7 @@ class CAccountingEntry if (!(mapValue.empty() && _ssExtra.empty())) { - CDataStream ss(nType, nVersion); + CDataStream ss(s.GetType(), nVersion); ss.insert(ss.begin(), '\0'); ss << mapValue; ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end()); @@ -927,7 +933,7 @@ class CAccountingEntry mapValue.clear(); if (std::string::npos != nSepPos) { - CDataStream ss(std::vector(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion); + CDataStream ss(std::vector(strComment.begin() + nSepPos + 1, strComment.end()), s.GetType(), s.GetVersion()); ss >> mapValue; _ssExtra = std::vector(ss.begin(), ss.end()); } diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 3ef718bd..6b9387bb 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -7,13 +7,13 @@ #include "base58.h" #include "consensus/validation.h" -#include "main.h" // For CheckTransaction +#include "processtx.h" // For CheckTransaction #include "protocol.h" #include "serialize.h" #include "sync.h" -#include "util.h" +#include "util/util.h" #include "args.h" -#include "utiltime.h" +#include "util/utiltime.h" #include "wallet/wallet.h" #include "wallet.h" @@ -622,8 +622,15 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) int nMinVersion = 0; if (Read((std::string)"minversion", nMinVersion)) { - if (nMinVersion > CLIENT_VERSION) + if (nMinVersion > WALLET_VERSION) + { return DB_TOO_NEW; + } + if (nMinVersion < FEATURE_WALLETCRYPT) // all ECC wallets support at least FEATURE_WALLETCRYPT + { + WriteMinVersion(FEATURE_LATEST); + nMinVersion = FEATURE_LATEST; + } pwallet->LoadMinVersion(nMinVersion); } diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 4f7df5b4..6d82d4d6 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -60,7 +60,7 @@ class CKeyMetadata ADD_SERIALIZE_METHODS template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(nCreateTime);