aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml5
-rwxr-xr-xautogen.sh3
-rw-r--r--build-aux/m4/bitcoin_qt.m439
-rw-r--r--configure.ac55
-rw-r--r--contrib/gitian-descriptors/boost-win.yml2
-rw-r--r--contrib/gitian-descriptors/deps-win.yml4
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml4
-rw-r--r--contrib/gitian-descriptors/protobuf-win.yml2
-rw-r--r--contrib/gitian-descriptors/qt-linux.yml4
-rw-r--r--contrib/gitian-descriptors/qt-win.yml2
-rw-r--r--contrib/linearize/example-linearize.cfg2
-rwxr-xr-xcontrib/linearize/linearize-data.py258
-rwxr-xr-xcontrib/linearize/linearize-hashes.py71
-rwxr-xr-xcontrib/macdeploy/macdeployqtplus26
-rw-r--r--depends/config.site.in4
-rw-r--r--depends/packages/bdb.mk2
-rw-r--r--depends/packages/native_comparisontool.mk6
-rw-r--r--doc/release-process.md4
-rwxr-xr-xqa/pull-tester/build-tests.sh.in1
-rwxr-xr-xqa/rpc-tests/forknotify.py65
-rwxr-xr-xqa/rpc-tests/send.sh2
-rwxr-xr-xqa/rpc-tests/walletbackup.sh2
-rw-r--r--share/qt/Info.plist.in3
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/alert.cpp37
-rw-r--r--src/alert.h3
-rw-r--r--src/amount.h4
-rw-r--r--src/bitcoin-tx.cpp22
-rw-r--r--src/chainparams.cpp41
-rw-r--r--src/chainparams.h24
-rw-r--r--src/chainparamsbase.cpp17
-rw-r--r--src/chainparamsbase.h1
-rw-r--r--src/checkpoints.cpp2
-rw-r--r--src/coins.cpp117
-rw-r--r--src/coins.h81
-rw-r--r--src/init.cpp16
-rw-r--r--src/main.cpp173
-rw-r--r--src/main.h16
-rw-r--r--src/miner.cpp11
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/netbase.h3
-rw-r--r--src/pow.cpp4
-rw-r--r--src/qt/bitcoinstrings.cpp16
-rw-r--r--src/qt/locale/bitcoin_en.ts346
-rw-r--r--src/qt/optionsmodel.cpp2
-rw-r--r--src/rpcblockchain.cpp2
-rw-r--r--src/rpcnet.cpp42
-rw-r--r--src/rpcrawtransaction.cpp29
-rw-r--r--src/rpcwallet.cpp19
-rw-r--r--src/script/interpreter.cpp161
-rw-r--r--src/script/interpreter.h58
-rw-r--r--src/script/sigcache.cpp88
-rw-r--r--src/script/sigcache.h26
-rw-r--r--src/script/sign.cpp8
-rw-r--r--src/script/standard.cpp15
-rw-r--r--src/serialize.h55
-rw-r--r--src/test/base58_tests.cpp4
-rw-r--r--src/test/canonical_tests.cpp113
-rw-r--r--src/test/coins_tests.cpp178
-rw-r--r--src/test/data/script_invalid.json133
-rw-r--r--src/test/data/script_valid.json133
-rw-r--r--src/test/miner_tests.cpp1
-rw-r--r--src/test/multisig_tests.cpp18
-rw-r--r--src/test/rpc_wallet_tests.cpp147
-rw-r--r--src/test/script_P2SH_tests.cpp9
-rw-r--r--src/test/script_tests.cpp184
-rw-r--r--src/test/test_bitcoin.cpp4
-rw-r--r--src/test/transaction_tests.cpp16
-rw-r--r--src/txdb.cpp23
-rw-r--r--src/txdb.h2
-rw-r--r--src/txmempool.cpp2
-rw-r--r--src/txmempool.h2
-rw-r--r--src/util.h1
-rw-r--r--src/wallet.cpp26
-rw-r--r--src/wallet.h8
-rw-r--r--src/walletdb.cpp7
77 files changed, 1930 insertions, 1092 deletions
diff --git a/.travis.yml b/.travis.yml
index eae07ead8e..89b2238655 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -31,7 +31,7 @@ matrix:
- compiler: "true 3"
env: HOST=x86_64-unknown-linux-gnu DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat"
- compiler: "true 4"
- env: HOST=i686-pc-linux-gnu PACKAGES="g++-multilib" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat"
+ env: HOST=i686-pc-linux-gnu PACKAGES="g++-multilib" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat" USE_SHELL="/bin/dash"
- compiler: "true 5"
env: HOST=x86_64-apple-darwin11 PACKAGES="gcc-multilib g++-multilib cmake libcap-dev libz-dev libbz2-dev" OSX_SDK=10.7 GOAL="deploy"
- compiler: "true 6"
@@ -48,11 +48,12 @@ before_script:
- 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 || (echo "Build failure. Verbose build follows." && make -C depends V=1 HOST=$HOST $DEP_OPTS)
script:
+ - 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
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then export CCACHE_READONLY=1; fi
- - ./autogen.sh
+ - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh
- ./configure --cache-file=config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false)
- make distdir PACKAGE=bitcoin VERSION=$HOST
- cd bitcoin-$HOST
diff --git a/autogen.sh b/autogen.sh
index ddfc09607e..3e26a18305 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -3,6 +3,7 @@ set -e
srcdir="$(dirname $0)"
cd "$srcdir"
if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then
- export LIBTOOLIZE="${GLIBTOOLIZE}"
+ LIBTOOLIZE="${GLIBTOOLIZE}"
+ export LIBTOOLIZE
fi
autoreconf --install --force --warnings=all
diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4
index edfde4cd79..2a72262653 100644
--- a/build-aux/m4/bitcoin_qt.m4
+++ b/build-aux/m4/bitcoin_qt.m4
@@ -84,7 +84,7 @@ 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
+ if test x$use_pkgconfig = x; then
use_pkgconfig=yes
fi
@@ -106,9 +106,9 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
BITCOIN_QT_CHECK([
TEMP_CPPFLAGS=$CPPFLAGS
CPPFLAGS=$QT_INCLUDES
- if test x$bitcoin_qt_got_major_vers == x5; then
+ if test x$bitcoin_qt_got_major_vers = x5; then
_BITCOIN_QT_IS_STATIC
- if test x$bitcoin_cv_static_qt == xyes; then
+ if test x$bitcoin_cv_static_qt = xyes; then
AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static])
if test x$qt_plugin_path != x; then
QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible"
@@ -118,14 +118,14 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"])
fi
_BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets])
- if test x$TARGET_OS == xwindows; then
+ 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
+ elif test x$TARGET_OS = xlinux; then
PKG_CHECK_MODULES([X11XCB], [x11-xcb], [QT_LIBS="$X11XCB_LIBS $QT_LIBS"])
_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
+ elif test x$TARGET_OS = xdarwin; then
if test x$use_pkgconfig = xyes; then
PKG_CHECK_MODULES([QTPRINT], [Qt5PrintSupport], [QT_LIBS="$QTPRINT_LIBS $QT_LIBS"])
fi
@@ -135,7 +135,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
fi
fi
else
- if test x$TARGET_OS == xwindows; then
+ if test x$TARGET_OS = xwindows; then
AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static])
if test x$qt_plugin_path != x; then
QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible"
@@ -152,6 +152,13 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
fi
CPPFLAGS=$TEMP_CPPFLAGS
])
+
+ 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
+
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)
@@ -189,7 +196,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
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
+ if test x$LUPDATE = x; then
AC_MSG_WARN("lupdate is required to update qt translations")
fi
],[
@@ -284,10 +291,10 @@ 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
+ 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
+ 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
@@ -297,14 +304,14 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG],[
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
+ 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
+ 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$have_qt = xno && test x$bitcoin_qt_want_version = xauto; then
if test x$auto_priority_version = x$qt5; 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
@@ -351,7 +358,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[
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
+ 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
@@ -366,7 +373,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[
LIBS="$LIBS -L$qt_lib_path"
fi
- if test x$TARGET_OS == xwindows; then
+ if test x$TARGET_OS = xwindows; then
AC_CHECK_LIB([imm32], [main],, BITCOIN_QT_FAIL(libimm32 not found))
fi
])
@@ -378,7 +385,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[
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
+ 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"
diff --git a/configure.ac b/configure.ac
index 7025249aba..87c7833bce 100644
--- a/configure.ac
+++ b/configure.ac
@@ -240,12 +240,27 @@ case $host in
AC_CHECK_PROG([BREW],brew, brew)
if test x$BREW = xbrew; then
- dnl add default homebrew paths
- openssl_prefix=`$BREW --prefix openssl`
- bdb_prefix=`$BREW --prefix berkeley-db4`
- export PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
- CPPFLAGS="$CPPFLAGS -I$bdb_prefix/include"
- LIBS="$LIBS -L$bdb_prefix/lib"
+ 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
@@ -274,7 +289,7 @@ if test x$use_comparison_tool != xno; then
fi
if test x$use_comparison_tool_reorg_tests != xno; then
- if test x$use_comparison_tool == x; 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)
@@ -282,20 +297,20 @@ else
AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 0)
fi
-if test x$use_lcov == xyes; then
- if test x$LCOV == x; then
+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
+ if test x$GCOV = x; then
AC_MSG_ERROR("lcov testing requested but gcov not found")
fi
- if test x$JAVA == x; then
+ if test x$JAVA = x; then
AC_MSG_ERROR("lcov testing requested but java not found")
fi
- if test x$GENHTML == x; then
+ 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
+ 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"
@@ -594,7 +609,7 @@ BITCOIN_QT_INIT
if test x$use_pkgconfig = xyes; then
- if test x"$PKG_CONFIG" == "x"; then
+ if test x"$PKG_CONFIG" = "x"; then
AC_MSG_ERROR(pkg-config not found.)
fi
@@ -708,7 +723,7 @@ if test x$bitcoin_enable_qt != xno; then
dnl enable qr support
AC_MSG_CHECKING([whether to build GUI with support for QR codes])
if test x$have_qrencode = xno; then
- if test x$use_qr == xyes; then
+ if test x$use_qr = xyes; then
AC_MSG_ERROR("QR support requested but cannot be built. use --without-qrencode")
fi
AC_MSG_RESULT(no)
@@ -722,7 +737,7 @@ if test x$bitcoin_enable_qt != xno; then
fi
fi
- if test x$XGETTEXT == x; then
+ if test x$XGETTEXT = x; then
AC_MSG_WARN("xgettext is required to update qt translations")
fi
@@ -757,12 +772,12 @@ 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$use_tests == xyes])
-AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt == xyes])
+AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes])
+AM_CONDITIONAL([ENABLE_TESTS],[test x$use_tests = xyes])
+AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes])
AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$use_tests$bitcoin_enable_qt_test = xyesyes])
AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes])
-AM_CONDITIONAL([USE_LCOV],[test x$use_lcov == xyes])
+AM_CONDITIONAL([USE_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])
diff --git a/contrib/gitian-descriptors/boost-win.yml b/contrib/gitian-descriptors/boost-win.yml
index db5d6bab1d..347952e3a6 100644
--- a/contrib/gitian-descriptors/boost-win.yml
+++ b/contrib/gitian-descriptors/boost-win.yml
@@ -29,7 +29,7 @@ script: |
#
INSTALLPREFIX=$HOME/staging${BITS}
BUILDDIR=$HOME/build${BITS}
- if [ "$BITS" == "32" ]; then
+ if [ "x$BITS" = "x32" ]; then
HOST=i686-w64-mingw32
else
HOST=x86_64-w64-mingw32
diff --git a/contrib/gitian-descriptors/deps-win.yml b/contrib/gitian-descriptors/deps-win.yml
index fabc2949eb..fe02950ef9 100644
--- a/contrib/gitian-descriptors/deps-win.yml
+++ b/contrib/gitian-descriptors/deps-win.yml
@@ -39,7 +39,7 @@ script: |
#
INSTALLPREFIX=$HOME/staging${BITS}
BUILDDIR=$HOME/build${BITS}
- if [ "$BITS" == "32" ]; then
+ if [ "x$BITS" = "x32" ]; then
HOST=i686-w64-mingw32
else
HOST=x86_64-w64-mingw32
@@ -50,7 +50,7 @@ script: |
#
tar xzf $INDIR/openssl-1.0.1h.tar.gz
cd openssl-1.0.1h
- if [ "$BITS" == "32" ]; then
+ if [ "x$BITS" = "x32" ]; then
OPENSSL_TGT=mingw
else
OPENSSL_TGT=mingw64
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index 245f15ccab..b2795c5376 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -50,7 +50,7 @@ script: |
STAGING=$HOME/staging${BITS}
BUILDDIR=$HOME/build${BITS}
BINDIR=$OUTDIR/$BITS
- if [ "$BITS" == "32" ]; then
+ if [ "x$BITS" = "x32" ]; then
HOST=i686-w64-mingw32
else
HOST=x86_64-w64-mingw32
@@ -63,7 +63,7 @@ script: |
unzip $INDIR/boost-win${BITS}-1.55.0-gitian-r6.zip
unzip $INDIR/bitcoin-deps-win${BITS}-gitian-r13.zip
unzip $INDIR/protobuf-win${BITS}-2.5.0-gitian-r4.zip
- if [ "$NEEDDIST" == "1" ]; then
+ if [ "x$NEEDDIST" = "x1" ]; then
# Make source code archive which is architecture independent so it only needs to be done once
cd $HOME/build/bitcoin
./autogen.sh
diff --git a/contrib/gitian-descriptors/protobuf-win.yml b/contrib/gitian-descriptors/protobuf-win.yml
index d2fdcaa7f2..1b7af08843 100644
--- a/contrib/gitian-descriptors/protobuf-win.yml
+++ b/contrib/gitian-descriptors/protobuf-win.yml
@@ -26,7 +26,7 @@ script: |
#
INSTALLPREFIX=$HOME/staging${BITS}
BUILDDIR=$HOME/build${BITS}
- if [ "$BITS" == "32" ]; then
+ if [ "x$BITS" = "x32" ]; then
HOST=i686-w64-mingw32
else
HOST=x86_64-w64-mingw32
diff --git a/contrib/gitian-descriptors/qt-linux.yml b/contrib/gitian-descriptors/qt-linux.yml
index b163b4bb8c..fd86b4df1d 100644
--- a/contrib/gitian-descriptors/qt-linux.yml
+++ b/contrib/gitian-descriptors/qt-linux.yml
@@ -18,7 +18,7 @@ files:
script: |
export FAKETIME=$REFERENCE_DATETIME
export TZ=UTC
- if [ "$GBUILD_BITS" == "32" ]; then
+ if [ "x$GBUILD_BITS" = "x32" ]; then
ARCH='i386-linux-gnu'
else
ARCH='x86_64-linux-gnu'
@@ -74,7 +74,7 @@ script: |
#endif
' > $QCONFIG
- if [ "$GBUILD_BITS" == "32" ]; then
+ if [ "x$GBUILD_BITS" = "x32" ]; then
echo '
/* Machine byte-order */
#define Q_BIG_ENDIAN 4321
diff --git a/contrib/gitian-descriptors/qt-win.yml b/contrib/gitian-descriptors/qt-win.yml
index 7000c70051..57bc4c3180 100644
--- a/contrib/gitian-descriptors/qt-win.yml
+++ b/contrib/gitian-descriptors/qt-win.yml
@@ -38,7 +38,7 @@ script: |
INSTALLPREFIX=$HOME/staging${BITS}
BUILDDIR=$HOME/build${BITS}
DEPSDIR=$HOME/deps${BITS}
- if [ "$BITS" == "32" ]; then
+ if [ "x$BITS" = "x32" ]; then
HOST=i686-w64-mingw32
else
HOST=x86_64-w64-mingw32
diff --git a/contrib/linearize/example-linearize.cfg b/contrib/linearize/example-linearize.cfg
index 071345f23a..e0fef13886 100644
--- a/contrib/linearize/example-linearize.cfg
+++ b/contrib/linearize/example-linearize.cfg
@@ -15,3 +15,5 @@ output_file=/home/example/Downloads/bootstrap.dat
hashlist=hashlist.txt
split_year=1
+# Maxmimum size in bytes of out-of-order blocks cache in memory
+out_of_order_cache_sz = 100000000
diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py
index 3b5d198c14..2dac3a614b 100755
--- a/contrib/linearize/linearize-data.py
+++ b/contrib/linearize/linearize-data.py
@@ -2,11 +2,12 @@
#
# linearize-data.py: Construct a linear, no-fork version of the chain.
#
-# Copyright (c) 2013 The Bitcoin developers
+# Copyright (c) 2013-2014 The Bitcoin developers
# Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
+from __future__ import print_function, division
import json
import struct
import re
@@ -17,10 +18,10 @@ import sys
import hashlib
import datetime
import time
+from collections import namedtuple
settings = {}
-
def uint32(x):
return x & 0xffffffffL
@@ -78,116 +79,174 @@ def get_block_hashes(settings):
return blkindex
-def mkblockset(blkindex):
+def mkblockmap(blkindex):
blkmap = {}
- for hash in blkindex:
- blkmap[hash] = True
+ for height,hash in enumerate(blkindex):
+ blkmap[hash] = height
return blkmap
-def copydata(settings, blkindex, blkset):
- inFn = 0
- inF = None
- outFn = 0
- outsz = 0
- outF = None
- outFname = None
- blkCount = 0
-
- lastDate = datetime.datetime(2000, 1, 1)
- highTS = 1408893517 - 315360000
- timestampSplit = False
- fileOutput = True
- setFileTime = False
- maxOutSz = settings['max_out_sz']
- if 'output' in settings:
- fileOutput = False
- if settings['file_timestamp'] != 0:
- setFileTime = True
- if settings['split_timestamp'] != 0:
- timestampSplit = True
-
- while True:
- if not inF:
- fname = "%s/blk%05d.dat" % (settings['input'], inFn)
- print("Input file" + fname)
- try:
- inF = open(fname, "rb")
- except IOError:
- print "Done"
- return
-
- inhdr = inF.read(8)
- if (not inhdr or (inhdr[0] == "\0")):
- inF.close()
- inF = None
- inFn = inFn + 1
- continue
-
- inMagic = inhdr[:4]
- if (inMagic != settings['netmagic']):
- print("Invalid magic:" + inMagic)
- return
- inLenLE = inhdr[4:]
- su = struct.unpack("<I", inLenLE)
- inLen = su[0]
- rawblock = inF.read(inLen)
- blk_hdr = rawblock[:80]
-
- hash_str = calc_hash_str(blk_hdr)
- if not hash_str in blkset:
- print("Skipping unknown block " + hash_str)
- continue
-
- if blkindex[blkCount] != hash_str:
- print("Out of order block.")
- print("Expected " + blkindex[blkCount])
- print("Got " + hash_str)
- sys.exit(1)
-
- if not fileOutput and ((outsz + inLen) > maxOutSz):
- outF.close()
- if setFileTime:
+# Block header and extent on disk
+BlockExtent = namedtuple('BlockExtent', ['fn', 'offset', 'inhdr', 'blkhdr', 'size'])
+
+class BlockDataCopier:
+ def __init__(self, settings, blkindex, blkmap):
+ self.settings = settings
+ self.blkindex = blkindex
+ self.blkmap = blkmap
+
+ self.inFn = 0
+ self.inF = None
+ self.outFn = 0
+ self.outsz = 0
+ self.outF = None
+ self.outFname = None
+ self.blkCountIn = 0
+ self.blkCountOut = 0
+
+ self.lastDate = datetime.datetime(2000, 1, 1)
+ self.highTS = 1408893517 - 315360000
+ self.timestampSplit = False
+ self.fileOutput = True
+ self.setFileTime = False
+ self.maxOutSz = settings['max_out_sz']
+ if 'output' in settings:
+ self.fileOutput = False
+ if settings['file_timestamp'] != 0:
+ self.setFileTime = True
+ if settings['split_timestamp'] != 0:
+ self.timestampSplit = True
+ # Extents and cache for out-of-order blocks
+ self.blockExtents = {}
+ self.outOfOrderData = {}
+ self.outOfOrderSize = 0 # running total size for items in outOfOrderData
+
+ def writeBlock(self, inhdr, blk_hdr, rawblock):
+ if not self.fileOutput and ((self.outsz + self.inLen) > self.maxOutSz):
+ self.outF.close()
+ if self.setFileTime:
os.utime(outFname, (int(time.time()), highTS))
- outF = None
- outFname = None
- outFn = outFn + 1
- outsz = 0
+ self.outF = None
+ self.outFname = None
+ self.outFn = outFn + 1
+ self.outsz = 0
(blkDate, blkTS) = get_blk_dt(blk_hdr)
- if timestampSplit and (blkDate > lastDate):
+ if self.timestampSplit and (blkDate > self.lastDate):
print("New month " + blkDate.strftime("%Y-%m") + " @ " + hash_str)
lastDate = blkDate
if outF:
outF.close()
if setFileTime:
os.utime(outFname, (int(time.time()), highTS))
- outF = None
- outFname = None
- outFn = outFn + 1
- outsz = 0
-
- if not outF:
- if fileOutput:
- outFname = settings['output_file']
+ self.outF = None
+ self.outFname = None
+ self.outFn = self.outFn + 1
+ self.outsz = 0
+
+ if not self.outF:
+ if self.fileOutput:
+ outFname = self.settings['output_file']
else:
- outFname = "%s/blk%05d.dat" % (settings['output'], outFn)
+ outFname = "%s/blk%05d.dat" % (self.settings['output'], outFn)
print("Output file" + outFname)
- outF = open(outFname, "wb")
-
- outF.write(inhdr)
- outF.write(rawblock)
- outsz = outsz + inLen + 8
-
- blkCount = blkCount + 1
- if blkTS > highTS:
- highTS = blkTS
-
- if (blkCount % 1000) == 0:
- print("Wrote " + str(blkCount) + " blocks")
+ self.outF = open(outFname, "wb")
+
+ self.outF.write(inhdr)
+ self.outF.write(blk_hdr)
+ self.outF.write(rawblock)
+ self.outsz = self.outsz + len(inhdr) + len(blk_hdr) + len(rawblock)
+
+ self.blkCountOut = self.blkCountOut + 1
+ if blkTS > self.highTS:
+ self.highTS = blkTS
+
+ if (self.blkCountOut % 1000) == 0:
+ print('%i blocks scanned, %i blocks written (of %i, %.1f%% complete)' %
+ (self.blkCountIn, self.blkCountOut, len(self.blkindex), 100.0 * self.blkCountOut / len(self.blkindex)))
+
+ def inFileName(self, fn):
+ return "%s/blk%05d.dat" % (self.settings['input'], fn)
+
+ def fetchBlock(self, extent):
+ '''Fetch block contents from disk given extents'''
+ with open(self.inFileName(extent.fn), "rb") as f:
+ f.seek(extent.offset)
+ return f.read(extent.size)
+
+ def copyOneBlock(self):
+ '''Find the next block to be written in the input, and copy it to the output.'''
+ extent = self.blockExtents.pop(self.blkCountOut)
+ if self.blkCountOut in self.outOfOrderData:
+ # If the data is cached, use it from memory and remove from the cache
+ rawblock = self.outOfOrderData.pop(self.blkCountOut)
+ self.outOfOrderSize -= len(rawblock)
+ else: # Otherwise look up data on disk
+ rawblock = self.fetchBlock(extent)
+
+ self.writeBlock(extent.inhdr, extent.blkhdr, rawblock)
+
+ def run(self):
+ while self.blkCountOut < len(self.blkindex):
+ if not self.inF:
+ fname = self.inFileName(self.inFn)
+ print("Input file" + fname)
+ try:
+ self.inF = open(fname, "rb")
+ except IOError:
+ print("Premature end of block data")
+ return
+
+ inhdr = self.inF.read(8)
+ if (not inhdr or (inhdr[0] == "\0")):
+ self.inF.close()
+ self.inF = None
+ self.inFn = self.inFn + 1
+ continue
+
+ inMagic = inhdr[:4]
+ if (inMagic != self.settings['netmagic']):
+ print("Invalid magic:" + inMagic)
+ return
+ inLenLE = inhdr[4:]
+ su = struct.unpack("<I", inLenLE)
+ inLen = su[0] - 80 # length without header
+ blk_hdr = self.inF.read(80)
+ inExtent = BlockExtent(self.inFn, self.inF.tell(), inhdr, blk_hdr, inLen)
+
+ hash_str = calc_hash_str(blk_hdr)
+ if not hash_str in blkmap:
+ print("Skipping unknown block " + hash_str)
+ self.inF.seek(inLen, os.SEEK_CUR)
+ continue
+
+ blkHeight = self.blkmap[hash_str]
+ self.blkCountIn += 1
+
+ if self.blkCountOut == blkHeight:
+ # If in-order block, just copy
+ rawblock = self.inF.read(inLen)
+ self.writeBlock(inhdr, blk_hdr, rawblock)
+
+ # See if we can catch up to prior out-of-order blocks
+ while self.blkCountOut in self.blockExtents:
+ self.copyOneBlock()
+
+ else: # If out-of-order, skip over block data for now
+ self.blockExtents[blkHeight] = inExtent
+ if self.outOfOrderSize < self.settings['out_of_order_cache_sz']:
+ # If there is space in the cache, read the data
+ # Reading the data in file sequence instead of seeking and fetching it later is preferred,
+ # but we don't want to fill up memory
+ self.outOfOrderData[blkHeight] = self.inF.read(inLen)
+ self.outOfOrderSize += inLen
+ else: # If no space in cache, seek forward
+ self.inF.seek(inLen, os.SEEK_CUR)
+
+ print("Done (%i blocks written)" % (self.blkCountOut))
if __name__ == '__main__':
if len(sys.argv) != 2:
- print "Usage: linearize-data.py CONFIG-FILE"
+ print("Usage: linearize-data.py CONFIG-FILE")
sys.exit(1)
f = open(sys.argv[1])
@@ -216,22 +275,25 @@ if __name__ == '__main__':
settings['split_timestamp'] = 0
if 'max_out_sz' not in settings:
settings['max_out_sz'] = 1000L * 1000 * 1000
+ if 'out_of_order_cache_sz' not in settings:
+ settings['out_of_order_cache_sz'] = 100 * 1000 * 1000
settings['max_out_sz'] = long(settings['max_out_sz'])
settings['split_timestamp'] = int(settings['split_timestamp'])
settings['file_timestamp'] = int(settings['file_timestamp'])
settings['netmagic'] = settings['netmagic'].decode('hex')
+ settings['out_of_order_cache_sz'] = int(settings['out_of_order_cache_sz'])
if 'output_file' not in settings and 'output' not in settings:
print("Missing output file / directory")
sys.exit(1)
blkindex = get_block_hashes(settings)
- blkset = mkblockset(blkindex)
+ blkmap = mkblockmap(blkindex)
- if not "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" in blkset:
+ if not "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" in blkmap:
print("not found")
else:
- copydata(settings, blkindex, blkset)
+ BlockDataCopier(settings, blkindex, blkmap).run()
diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py
index 791b71bc33..dc7f654049 100755
--- a/contrib/linearize/linearize-hashes.py
+++ b/contrib/linearize/linearize-hashes.py
@@ -2,11 +2,12 @@
#
# linearize-hashes.py: List blocks in a linear, no-fork version of the chain.
#
-# Copyright (c) 2013 The Bitcoin developers
+# Copyright (c) 2013-2014 The Bitcoin developers
# Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
+from __future__ import print_function
import json
import struct
import re
@@ -17,59 +18,65 @@ import sys
settings = {}
class BitcoinRPC:
- OBJID = 1
-
def __init__(self, host, port, username, password):
authpair = "%s:%s" % (username, password)
self.authhdr = "Basic %s" % (base64.b64encode(authpair))
self.conn = httplib.HTTPConnection(host, port, False, 30)
- def rpc(self, method, params=None):
- self.OBJID += 1
- obj = { 'version' : '1.1',
- 'method' : method,
- 'id' : self.OBJID }
- if params is None:
- obj['params'] = []
- else:
- obj['params'] = params
+
+ def execute(self, obj):
self.conn.request('POST', '/', json.dumps(obj),
{ 'Authorization' : self.authhdr,
'Content-type' : 'application/json' })
resp = self.conn.getresponse()
if resp is None:
- print "JSON-RPC: no response"
+ print("JSON-RPC: no response", file=sys.stderr)
return None
body = resp.read()
resp_obj = json.loads(body)
- if resp_obj is None:
- print "JSON-RPC: cannot JSON-decode body"
- return None
- if 'error' in resp_obj and resp_obj['error'] != None:
- return resp_obj['error']
- if 'result' not in resp_obj:
- print "JSON-RPC: no result in object"
- return None
+ return resp_obj
- return resp_obj['result']
- def getblock(self, hash, verbose=True):
- return self.rpc('getblock', [hash, verbose])
- def getblockhash(self, index):
- return self.rpc('getblockhash', [index])
+ @staticmethod
+ def build_request(idx, method, params):
+ obj = { 'version' : '1.1',
+ 'method' : method,
+ 'id' : idx }
+ if params is None:
+ obj['params'] = []
+ else:
+ obj['params'] = params
+ return obj
+
+ @staticmethod
+ def response_is_error(resp_obj):
+ return 'error' in resp_obj and resp_obj['error'] is not None
-def get_block_hashes(settings):
+def get_block_hashes(settings, max_blocks_per_call=10000):
rpc = BitcoinRPC(settings['host'], settings['port'],
settings['rpcuser'], settings['rpcpassword'])
- for height in xrange(settings['min_height'], settings['max_height']+1):
- hash = rpc.getblockhash(height)
+ height = settings['min_height']
+ while height < settings['max_height']+1:
+ num_blocks = min(settings['max_height']+1-height, max_blocks_per_call)
+ batch = []
+ for x in range(num_blocks):
+ batch.append(rpc.build_request(x, 'getblockhash', [height + x]))
+
+ reply = rpc.execute(batch)
+
+ for x,resp_obj in enumerate(reply):
+ if rpc.response_is_error(resp_obj):
+ print('JSON-RPC: error at height', height+x, ': ', resp_obj['error'], file=sys.stderr)
+ exit(1)
+ assert(resp_obj['id'] == x) # assume replies are in-sequence
+ print(resp_obj['result'])
- print(hash)
+ height += num_blocks
if __name__ == '__main__':
if len(sys.argv) != 2:
- print "Usage: linearize-hashes.py CONFIG-FILE"
+ print("Usage: linearize-hashes.py CONFIG-FILE")
sys.exit(1)
f = open(sys.argv[1])
@@ -95,7 +102,7 @@ if __name__ == '__main__':
if 'max_height' not in settings:
settings['max_height'] = 313000
if 'rpcuser' not in settings or 'rpcpassword' not in settings:
- print "Missing username and/or password in cfg file"
+ print("Missing username and/or password in cfg file", file=stderr)
sys.exit(1)
settings['port'] = int(settings['port'])
diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus
index 8f826ace09..541136001f 100755
--- a/contrib/macdeploy/macdeployqtplus
+++ b/contrib/macdeploy/macdeployqtplus
@@ -393,7 +393,7 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
# Deploy the script plugins only if QtScript is in use
if not deploymentInfo.usesFramework("QtScript"):
continue
- elif pluginDirectory == "qmltooling":
+ elif pluginDirectory == "qmltooling" or pluginDirectory == "qml1tooling":
# Deploy the qml plugins only if QtDeclarative is in use
if not deploymentInfo.usesFramework("QtDeclarative"):
continue
@@ -401,7 +401,23 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
# Deploy the bearer plugins only if QtNetwork is in use
if not deploymentInfo.usesFramework("QtNetwork"):
continue
-
+ elif pluginDirectory == "position":
+ # Deploy the position plugins only if QtPositioning is in use
+ if not deploymentInfo.usesFramework("QtPositioning"):
+ continue
+ elif pluginDirectory == "sensors" or pluginDirectory == "sensorgestures":
+ # Deploy the sensor plugins only if QtSensors is in use
+ if not deploymentInfo.usesFramework("QtSensors"):
+ continue
+ elif pluginDirectory == "audio" or pluginDirectory == "playlistformats":
+ # Deploy the audio plugins only if QtMultimedia is in use
+ if not deploymentInfo.usesFramework("QtMultimedia"):
+ continue
+ elif pluginDirectory == "mediaservice":
+ # Deploy the mediaservice plugins only if QtMultimediaWidgets is in use
+ if not deploymentInfo.usesFramework("QtMultimediaWidgets"):
+ continue
+
for pluginName in filenames:
pluginPath = os.path.join(pluginDirectory, pluginName)
if pluginName.endswith("_debug.dylib"):
@@ -419,7 +435,11 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
# Deploy the opengl graphicssystem plugin only if QtOpenGL is in use
if not deploymentInfo.usesFramework("QtOpenGL"):
continue
-
+ elif pluginPath == "accessible/libqtaccessiblequick.dylib":
+ # Deploy the accessible qtquick plugin only if QtQuick is in use
+ if not deploymentInfo.usesFramework("QtQuick"):
+ continue
+
plugins.append((pluginDirectory, pluginName))
for pluginDirectory, pluginName in plugins:
diff --git a/depends/config.site.in b/depends/config.site.in
index 3426050cd3..df076956bd 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -34,12 +34,12 @@ if test -z $with_gui && test -n "@no_qt@"; then
with_gui=no
fi
-if test @host_os@ == darwin; then
+if test x@host_os@ = xdarwin; then
BREW=no
PORT=no
fi
-if test @host_os@ == mingw32; then
+if test x@host_os@ = xmingw32; then
if test -z $with_qt_incdir; then
with_qt_incdir=$prefix/include
fi
diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk
index 503409c5e5..f39925723b 100644
--- a/depends/packages/bdb.mk
+++ b/depends/packages/bdb.mk
@@ -6,7 +6,7 @@ $(package)_sha256_hash=12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b857327
$(package)_build_subdir=build_unix
define $(package)_set_vars
-$(package)_config_opts=--disable-shared --enable-cxx
+$(package)_config_opts=--disable-shared --enable-cxx --disable-replication
$(package)_config_opts_mingw32=--enable-mingw
$(package)_config_opts_x86_64_linux=--with-pic
$(package)_config_opts_arm_linux=--with-pic
diff --git a/depends/packages/native_comparisontool.mk b/depends/packages/native_comparisontool.mk
index 4c40f8b123..3d430d4306 100644
--- a/depends/packages/native_comparisontool.mk
+++ b/depends/packages/native_comparisontool.mk
@@ -1,8 +1,8 @@
package=native_comparisontool
-$(package)_version=5caed78
-$(package)_download_path=https://github.com/TheBlueMatt/test-scripts/raw/2d76ce92d68e6746988adde731318605a70e252c
+$(package)_version=0f7b5d8
+$(package)_download_path=https://github.com/TheBlueMatt/test-scripts/raw/38b490a2599d422b12d5ce8f165792f63fd8f54f
$(package)_file_name=pull-tests-$($(package)_version).jar
-$(package)_sha256_hash=b55a98828b17060e327c5dabe5e4631898f422c0cba07c46170930a9eaf5e7c0
+$(package)_sha256_hash=ecd43b988a8b673b483e4f69f931596360a5e90fc415c75c4c259faa690df198
$(package)_install_dirname=BitcoindComparisonTool_jar
$(package)_install_filename=BitcoindComparisonTool.jar
diff --git a/doc/release-process.md b/doc/release-process.md
index 940f934baf..7699af90bd 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -154,6 +154,10 @@ repackage gitian builds for release as stand-alone zip/tar/installer exe
zip -r bitcoin-${VERSION}-win.zip bitcoin-${VERSION}-win
rm -rf bitcoin-${VERSION}-win
+**Mac OS X .dmg:**
+
+ mv Bitcoin-Qt.dmg bitcoin-${VERSION}-osx.dmg
+
###Next steps:
Commit your signature to gitian.sigs:
diff --git a/qa/pull-tester/build-tests.sh.in b/qa/pull-tester/build-tests.sh.in
index ebf377a489..1ef47d77f4 100755
--- a/qa/pull-tester/build-tests.sh.in
+++ b/qa/pull-tester/build-tests.sh.in
@@ -75,6 +75,7 @@ make check
# Run RPC integration test on Linux:
@abs_top_srcdir@/qa/rpc-tests/wallet.sh @abs_top_srcdir@/linux-build/src
@abs_top_srcdir@/qa/rpc-tests/listtransactions.py --srcdir @abs_top_srcdir@/linux-build/src
+@abs_top_srcdir@/qa/rpc-tests/forknotify.py --srcdir @abs_top_srcdir@/linux-build/src
# Clean up cache/ directory that the python regression tests create
rm -rf cache
diff --git a/qa/rpc-tests/forknotify.py b/qa/rpc-tests/forknotify.py
new file mode 100755
index 0000000000..a482f7cc5a
--- /dev/null
+++ b/qa/rpc-tests/forknotify.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 The Bitcoin Core developers
+# Distributed under the MIT/X11 software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#
+# Test -alertnotify
+#
+
+from test_framework import BitcoinTestFramework
+from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
+from util import *
+import os
+import shutil
+
+class ForkNotifyTest(BitcoinTestFramework):
+
+ alert_filename = None # Set by setup_network
+
+ def setup_network(self, test_dir):
+ nodes = []
+ self.alert_filename = os.path.join(test_dir, "alert.txt")
+ with open(self.alert_filename, 'w') as f:
+ pass # Just open then close to create zero-length file
+ nodes.append(start_node(0, test_dir,
+ ["-blockversion=2", "-alertnotify=echo %s >> '" + self.alert_filename + "'"]))
+ # Node1 mines block.version=211 blocks
+ nodes.append(start_node(1, test_dir,
+ ["-blockversion=211"]))
+ connect_nodes(nodes[1], 0)
+
+ sync_blocks(nodes)
+ return nodes
+
+
+ def run_test(self, nodes):
+ # Mine 51 up-version blocks
+ nodes[1].setgenerate(True, 51)
+ sync_blocks(nodes)
+ # -alertnotify should trigger on the 51'st,
+ # but mine and sync another to give
+ # -alertnotify time to write
+ nodes[1].setgenerate(True, 1)
+ sync_blocks(nodes)
+
+ 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:
+ nodes[1].setgenerate(True, 1)
+ sync_blocks(nodes)
+ nodes[1].setgenerate(True, 1)
+ sync_blocks(nodes)
+
+ 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/send.sh b/qa/rpc-tests/send.sh
index bfbf791d07..8c0f114590 100755
--- a/qa/rpc-tests/send.sh
+++ b/qa/rpc-tests/send.sh
@@ -14,7 +14,7 @@ if [ $# -eq 0 ]; then
exit 0
fi
-if [ $1 == "-STOP" ]; then
+if [ $1 = "-STOP" ]; then
if [ -s ${PIDFILE} ]; then
kill -s ${SIGNAL} $(<${PIDFILE})
fi
diff --git a/qa/rpc-tests/walletbackup.sh b/qa/rpc-tests/walletbackup.sh
index 7444670980..b88d5920f7 100755
--- a/qa/rpc-tests/walletbackup.sh
+++ b/qa/rpc-tests/walletbackup.sh
@@ -149,7 +149,7 @@ echo "Creating transactions..."
function S {
TXID=$( $CLI -datadir=${D}/node${1} sendtoaddress ${2} "${3}" 0 )
- if [[ $TXID == "" ]] ; then
+ if [ x$TXID = x ] ; then
echoerr "node${1}: error sending ${3} btc"
echo -n "node${1} balance: "
$CLI -datadir=${D}/node${1} getbalance "*" 0
diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in
index e79e59a568..dd6edde8d2 100644
--- a/share/qt/Info.plist.in
+++ b/share/qt/Info.plist.in
@@ -91,6 +91,9 @@
<key>NSHighResolutionCapable</key>
<string>True</string>
+ <key>LSAppNapIsDisabled</key>
+ <string>True</string>
+
<key>LSApplicationCategoryType</key>
<string>public.app-category.finance</string>
</dict>
diff --git a/src/Makefile.am b/src/Makefile.am
index bd6f1ba0d5..155adfef7d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -103,6 +103,7 @@ BITCOIN_CORE_H = \
script/compressor.h \
script/interpreter.h \
script/script.h \
+ script/sigcache.h \
script/sign.h \
script/standard.h \
serialize.h \
@@ -218,6 +219,7 @@ libbitcoin_common_a_SOURCES = \
script/compressor.cpp \
script/interpreter.cpp \
script/script.cpp \
+ script/sigcache.cpp \
script/sign.cpp \
script/standard.cpp \
$(BITCOIN_CORE_H)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index ab449f3e71..b20e226c3d 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -40,10 +40,10 @@ BITCOIN_TESTS =\
test/base58_tests.cpp \
test/base64_tests.cpp \
test/bloom_tests.cpp \
- test/canonical_tests.cpp \
test/checkblock_tests.cpp \
test/Checkpoints_tests.cpp \
test/compress_tests.cpp \
+ test/coins_tests.cpp \
test/crypto_tests.cpp \
test/DoS_tests.cpp \
test/getarg_tests.cpp \
diff --git a/src/alert.cpp b/src/alert.cpp
index 3271ecfbfd..d495849206 100644
--- a/src/alert.cpp
+++ b/src/alert.cpp
@@ -233,25 +233,30 @@ bool CAlert::ProcessAlert(bool fThread)
if(AppliesToMe())
{
uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
- std::string strCmd = GetArg("-alertnotify", "");
- if (!strCmd.empty())
- {
- // Alert text should be plain ascii coming from a trusted source, but to
- // be safe we first strip anything not in safeChars, then add single quotes around
- // the whole string before passing it to the shell:
- std::string singleQuote("'");
- std::string safeStatus = SanitizeString(strStatusBar);
- safeStatus = singleQuote+safeStatus+singleQuote;
- boost::replace_all(strCmd, "%s", safeStatus);
-
- if (fThread)
- boost::thread t(runCommand, strCmd); // thread runs free
- else
- runCommand(strCmd);
- }
+ Notify(strStatusBar, fThread);
}
}
LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
return true;
}
+
+void
+CAlert::Notify(const std::string& strMessage, bool fThread)
+{
+ std::string strCmd = GetArg("-alertnotify", "");
+ if (strCmd.empty()) return;
+
+ // Alert text should be plain ascii coming from a trusted source, but to
+ // be safe we first strip anything not in safeChars, then add single quotes around
+ // the whole string before passing it to the shell:
+ std::string singleQuote("'");
+ std::string safeStatus = SanitizeString(strMessage);
+ safeStatus = singleQuote+safeStatus+singleQuote;
+ boost::replace_all(strCmd, "%s", safeStatus);
+
+ if (fThread)
+ boost::thread t(runCommand, strCmd); // thread runs free
+ else
+ runCommand(strCmd);
+}
diff --git a/src/alert.h b/src/alert.h
index 5ecf94cea8..ba3235858d 100644
--- a/src/alert.h
+++ b/src/alert.h
@@ -101,7 +101,8 @@ public:
bool AppliesToMe() const;
bool RelayTo(CNode* pnode) const;
bool CheckSignature() const;
- bool ProcessAlert(bool fThread = true);
+ bool ProcessAlert(bool fThread = true); // fThread means run -alertnotify in a free-running thread
+ static void Notify(const std::string& strMessage, bool fThread);
/*
* Get copy of (active) alert object by hash. Returns a null alert if it is not found.
diff --git a/src/amount.h b/src/amount.h
index 42006a0388..831fa1f6ca 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_AMOUNT_H
@@ -10,4 +10,4 @@
typedef int64_t CAmount;
-#endif
+#endif // BITCOIN_AMOUNT_H
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index a61b4fe29d..da37e60c7f 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -340,7 +340,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
CMutableTransaction mergedTx(txVariants[0]);
bool fComplete = true;
CCoinsView viewDummy;
- CCoinsViewCache view(viewDummy);
+ CCoinsViewCache view(&viewDummy);
if (!registers.count("privatekeys"))
throw runtime_error("privatekeys register variable must be set.");
@@ -384,21 +384,19 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
vector<unsigned char> pkData(ParseHexUV(prevOut, "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
- CCoins coins;
- if (view.GetCoins(txid, coins)) {
- if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
+ {
+ CCoinsModifier coins = view.ModifyCoins(txid);
+ if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
string err("Previous output scriptPubKey mismatch:\n");
- err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
+ err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
scriptPubKey.ToString();
throw runtime_error(err);
}
- // what todo if txid is known, but the actual output isn't?
+ if ((unsigned int)nOut >= coins->vout.size())
+ coins->vout.resize(nOut+1);
+ coins->vout[nOut].scriptPubKey = scriptPubKey;
+ coins->vout[nOut].nValue = 0; // we don't know the actual output value
}
- if ((unsigned int)nOut >= coins.vout.size())
- coins.vout.resize(nOut+1);
- coins.vout[nOut].scriptPubKey = scriptPubKey;
- coins.vout[nOut].nValue = 0; // we don't know the actual output value
- view.SetCoins(txid, coins);
// if redeemScript given and private keys given,
// add redeemScript to the tempKeystore so it can be signed:
@@ -435,7 +433,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
BOOST_FOREACH(const CTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
- if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STANDARD_SCRIPT_VERIFY_FLAGS))
+ if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(mergedTx, i)))
fComplete = false;
}
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 179db5a818..31c67715c8 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -115,6 +115,7 @@ public:
fAllowMinDifficultyBlocks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
+ fSkipProofOfWorkCheck = false;
}
};
static CMainParams mainParams;
@@ -214,8 +215,46 @@ public:
};
static CRegTestParams regTestParams;
+//
+// Unit test
+//
+class CUnitTestParams : public CMainParams, public CModifiableParams {
+public:
+ CUnitTestParams() {
+ networkID = CBaseChainParams::UNITTEST;
+ strNetworkID = "unittest";
+ nDefaultPort = 18445;
+ vFixedSeeds.clear();
+ vSeeds.clear(); // Regtest mode doesn't have any DNS seeds.
+
+ fRequireRPCPassword = false;
+ fMiningRequiresPeers = false;
+ fDefaultCheckMemPool = true;
+ fAllowMinDifficultyBlocks = false;
+ fMineBlocksOnDemand = true;
+ }
+public:
+ // Published setters to allow changing values in unit test cases
+ virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) { nSubsidyHalvingInterval=anSubsidyHalvingInterval; }
+ virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority) { nEnforceBlockUpgradeMajority=anEnforceBlockUpgradeMajority; }
+ virtual void setRejectBlockOutdatedMajority(int anRejectBlockOutdatedMajority) { nRejectBlockOutdatedMajority=anRejectBlockOutdatedMajority; }
+ virtual void setToCheckBlockUpgradeMajority(int anToCheckBlockUpgradeMajority) { nToCheckBlockUpgradeMajority=anToCheckBlockUpgradeMajority; }
+ virtual void setDefaultCheckMemPool(bool afDefaultCheckMemPool) { fDefaultCheckMemPool=afDefaultCheckMemPool; }
+ virtual void setAllowMinDifficultyBlocks(bool afAllowMinDifficultyBlocks) { fAllowMinDifficultyBlocks=afAllowMinDifficultyBlocks; }
+ virtual void setSkipProofOfWorkCheck(bool afSkipProofOfWorkCheck) { fSkipProofOfWorkCheck = afSkipProofOfWorkCheck; }
+};
+static CUnitTestParams unitTestParams;
+
+
static CChainParams *pCurrentParams = 0;
+CModifiableParams *ModifiableParams()
+{
+ assert(pCurrentParams);
+ assert(pCurrentParams==&unitTestParams);
+ return (CModifiableParams*)&unitTestParams;
+}
+
const CChainParams &Params() {
assert(pCurrentParams);
return *pCurrentParams;
@@ -229,6 +268,8 @@ CChainParams &Params(CBaseChainParams::Network network) {
return testNetParams;
case CBaseChainParams::REGTEST:
return regTestParams;
+ case CBaseChainParams::UNITTEST:
+ return unitTestParams;
default:
assert(false && "Unimplemented network");
return mainParams;
diff --git a/src/chainparams.h b/src/chainparams.h
index e5dfc87c6d..50441a89f3 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -61,6 +61,8 @@ public:
bool DefaultCheckMemPool() const { return fDefaultCheckMemPool; }
/* Allow mining of a min-difficulty block */
bool AllowMinDifficultyBlocks() const { return fAllowMinDifficultyBlocks; }
+ /* Skip proof-of-work check: allow mining of any difficulty block */
+ bool SkipProofOfWorkCheck() const { return fSkipProofOfWorkCheck; }
/* Make standard checks */
bool RequireStandard() const { return fRequireStandard; }
int64_t TargetTimespan() const { return nTargetTimespan; }
@@ -103,8 +105,27 @@ protected:
bool fAllowMinDifficultyBlocks;
bool fRequireStandard;
bool fMineBlocksOnDemand;
+ bool fSkipProofOfWorkCheck;
};
+/** Modifiable parameters interface is used by test cases to adapt the parameters in order
+*** to test specific features more easily. Test cases should always restore the previous
+*** values after finalization.
+**/
+
+class CModifiableParams {
+public:
+ // Published setters to allow changing values in unit test cases
+ virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) =0;
+ virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority)=0;
+ virtual void setRejectBlockOutdatedMajority(int anRejectBlockOutdatedMajority)=0;
+ virtual void setToCheckBlockUpgradeMajority(int anToCheckBlockUpgradeMajority)=0;
+ virtual void setDefaultCheckMemPool(bool aDefaultCheckMemPool)=0;
+ virtual void setAllowMinDifficultyBlocks(bool aAllowMinDifficultyBlocks)=0;
+ virtual void setSkipProofOfWorkCheck(bool aSkipProofOfWorkCheck)=0;
+};
+
+
/**
* Return the currently selected parameters. This won't change after app startup
* outside of the unit tests.
@@ -114,6 +135,9 @@ const CChainParams &Params();
/** Return parameters for the given network. */
CChainParams &Params(CBaseChainParams::Network network);
+/** Get modifyable network parameters (UNITTEST only) */
+CModifiableParams *ModifiableParams();
+
/** Sets the params returned by Params() to those for the given network. */
void SelectParams(CBaseChainParams::Network network);
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 98bb5b855f..e9d63197bd 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -57,6 +57,20 @@ public:
};
static CBaseRegTestParams regTestParams;
+//
+// Unit test
+//
+class CBaseUnitTestParams : public CBaseMainParams
+{
+public:
+ CBaseUnitTestParams()
+ {
+ networkID = CBaseChainParams::UNITTEST;
+ strDataDir = "unittest";
+ }
+};
+static CBaseUnitTestParams unitTestParams;
+
static CBaseChainParams* pCurrentBaseParams = 0;
const CBaseChainParams& BaseParams()
@@ -77,6 +91,9 @@ void SelectBaseParams(CBaseChainParams::Network network)
case CBaseChainParams::REGTEST:
pCurrentBaseParams = &regTestParams;
break;
+ case CBaseChainParams::UNITTEST:
+ pCurrentBaseParams = &unitTestParams;
+ break;
default:
assert(false && "Unimplemented network");
return;
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index c054f03f17..cc154cf501 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -19,6 +19,7 @@ public:
MAIN,
TESTNET,
REGTEST,
+ UNITTEST,
MAX_NETWORK_TYPES
};
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index c41deea7ce..9a6bc05e63 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -88,6 +88,8 @@ namespace Checkpoints {
return dataTestnet;
else if (Params().NetworkID() == CBaseChainParams::MAIN)
return data;
+ else if (Params().NetworkID() == CBaseChainParams::UNITTEST) // UnitTest share the same checkpoints as MAIN
+ return data;
else
return dataRegtest;
}
diff --git a/src/coins.cpp b/src/coins.cpp
index 9b8d63d4e4..e4f3e67aeb 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -53,61 +53,72 @@ bool CCoins::Spend(int nPos) {
bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
-bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; }
bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(0); }
-bool CCoinsView::SetBestBlock(const uint256 &hashBlock) { return false; }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
-CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { }
+CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
-bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); }
bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
-bool CCoinsViewBacked::SetBestBlock(const uint256 &hashBlock) { return base->SetBestBlock(hashBlock); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
-CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), hashBlock(0) { }
+CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), hashBlock(0) { }
-bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
- if (cacheCoins.count(txid)) {
- coins = cacheCoins[txid];
- return true;
- }
- if (base->GetCoins(txid, coins)) {
- cacheCoins[txid] = coins;
- return true;
- }
- return false;
+CCoinsViewCache::~CCoinsViewCache()
+{
+ assert(!hasModifier);
}
-CCoinsMap::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) {
+CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const {
CCoinsMap::iterator it = cacheCoins.find(txid);
if (it != cacheCoins.end())
return it;
CCoins tmp;
- if (!base->GetCoins(txid,tmp))
+ if (!base->GetCoins(txid, tmp))
return cacheCoins.end();
- CCoinsMap::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins()));
- tmp.swap(ret->second);
+ CCoinsMap::iterator ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())).first;
+ tmp.swap(ret->second.coins);
+ if (ret->second.coins.IsPruned()) {
+ // The parent only has an empty entry for this txid; we can consider our
+ // version as fresh.
+ ret->second.flags = CCoinsCacheEntry::FRESH;
+ }
return ret;
}
-CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const {
- /* Avoid redundant implementation with the const-cast. */
- return const_cast<CCoinsViewCache*>(this)->FetchCoins(txid);
+bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
+ CCoinsMap::const_iterator it = FetchCoins(txid);
+ if (it != cacheCoins.end()) {
+ coins = it->second.coins;
+ return true;
+ }
+ return false;
}
-CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) {
- CCoinsMap::iterator it = FetchCoins(txid);
- assert(it != cacheCoins.end());
- return it->second;
+CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) {
+ assert(!hasModifier);
+ hasModifier = true;
+ std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry()));
+ if (ret.second) {
+ if (!base->GetCoins(txid, ret.first->second.coins)) {
+ // The parent view does not have this entry; mark it as fresh.
+ ret.first->second.coins.Clear();
+ ret.first->second.flags = CCoinsCacheEntry::FRESH;
+ } else if (ret.first->second.coins.IsPruned()) {
+ // The parent view only has a pruned entry for this; mark it as fresh.
+ ret.first->second.flags = CCoinsCacheEntry::FRESH;
+ }
+ }
+ // Assume that whenever ModifyCoins is called, the entry will be modified.
+ ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
+ return CCoinsModifier(*this, ret.first);
}
const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
@@ -115,22 +126,17 @@ const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
if (it == cacheCoins.end()) {
return NULL;
} else {
- return &it->second;
+ return &it->second.coins;
}
}
-bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) {
- cacheCoins[txid] = coins;
- return true;
-}
-
bool CCoinsViewCache::HaveCoins(const uint256 &txid) const {
CCoinsMap::const_iterator it = FetchCoins(txid);
// We're using vtx.empty() instead of IsPruned here for performance reasons,
// as we only care about the case where an transaction was replaced entirely
// in a reorganization (which wipes vout entirely, as opposed to spending
// which just cleans individual outputs).
- return (it != cacheCoins.end() && !it->second.vout.empty());
+ return (it != cacheCoins.end() && !it->second.coins.vout.empty());
}
uint256 CCoinsViewCache::GetBestBlock() const {
@@ -139,14 +145,39 @@ uint256 CCoinsViewCache::GetBestBlock() const {
return hashBlock;
}
-bool CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
+void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
hashBlock = hashBlockIn;
- return true;
}
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
+ assert(!hasModifier);
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
- cacheCoins[it->first].swap(it->second);
+ if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
+ CCoinsMap::iterator itUs = cacheCoins.find(it->first);
+ if (itUs == cacheCoins.end()) {
+ if (!it->second.coins.IsPruned()) {
+ // The parent cache does not have an entry, while the child
+ // cache does have (a non-pruned) one. Move the data up, and
+ // mark it as fresh (if the grandparent did have it, we
+ // would have pulled it in at first GetCoins).
+ assert(it->second.flags & CCoinsCacheEntry::FRESH);
+ CCoinsCacheEntry& entry = cacheCoins[it->first];
+ entry.coins.swap(it->second.coins);
+ entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH;
+ }
+ } else {
+ if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
+ // The grandparent does not have an entry, and the child is
+ // modified and being pruned. This means we can just delete
+ // it from the parent.
+ cacheCoins.erase(itUs);
+ } else {
+ // A normal modification.
+ itUs->second.coins.swap(it->second.coins);
+ itUs->second.flags |= CCoinsCacheEntry::DIRTY;
+ }
+ }
+ }
CCoinsMap::iterator itOld = it++;
mapCoins.erase(itOld);
}
@@ -213,3 +244,15 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
}
return tx.ComputePriority(dResult);
}
+
+CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_) : cache(cache_), it(it_) {}
+
+CCoinsModifier::~CCoinsModifier()
+{
+ assert(cache.hasModifier);
+ cache.hasModifier = false;
+ it->second.coins.Cleanup();
+ if ((it->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
+ cache.cacheCoins.erase(it);
+ }
+}
diff --git a/src/coins.h b/src/coins.h
index 2583475323..b8f1e5bcc5 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -83,11 +83,26 @@ public:
// as new tx version will probably only be introduced at certain heights
int nVersion;
- // construct a CCoins from a CTransaction, at a given height
- CCoins(const CTransaction &tx, int nHeightIn) : fCoinBase(tx.IsCoinBase()), vout(tx.vout), nHeight(nHeightIn), nVersion(tx.nVersion) {
+ void FromTx(const CTransaction &tx, int nHeightIn) {
+ fCoinBase = tx.IsCoinBase();
+ vout = tx.vout;
+ nHeight = nHeightIn;
+ nVersion = tx.nVersion;
ClearUnspendable();
}
+ // construct a CCoins from a CTransaction, at a given height
+ CCoins(const CTransaction &tx, int nHeightIn) {
+ FromTx(tx, nHeightIn);
+ }
+
+ void Clear() {
+ fCoinBase = false;
+ std::vector<CTxOut>().swap(vout);
+ nHeight = 0;
+ nVersion = 0;
+ }
+
// empty constructor
CCoins() : fCoinBase(false), vout(0), nHeight(0), nVersion(0) { }
@@ -256,7 +271,20 @@ public:
}
};
-typedef boost::unordered_map<uint256, CCoins, CCoinsKeyHasher> CCoinsMap;
+struct CCoinsCacheEntry
+{
+ CCoins coins; // The actual cached data.
+ unsigned char flags;
+
+ enum Flags {
+ DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
+ FRESH = (1 << 1), // The parent view does not have this entry (or it is pruned).
+ };
+
+ CCoinsCacheEntry() : coins(), flags(0) {}
+};
+
+typedef boost::unordered_map<uint256, CCoinsCacheEntry, CCoinsKeyHasher> CCoinsMap;
struct CCoinsStats
{
@@ -279,9 +307,6 @@ public:
// Retrieve the CCoins (unspent transaction outputs) for a given txid
virtual bool GetCoins(const uint256 &txid, CCoins &coins) const;
- // Modify the CCoins for a given txid
- virtual bool SetCoins(const uint256 &txid, const CCoins &coins);
-
// Just check whether we have data for a given txid.
// This may (but cannot always) return true for fully spent transactions
virtual bool HaveCoins(const uint256 &txid) const;
@@ -289,10 +314,7 @@ public:
// Retrieve the block hash whose state this CCoinsView currently represents
virtual uint256 GetBestBlock() const;
- // Modify the currently active block hash
- virtual bool SetBestBlock(const uint256 &hashBlock);
-
- // Do a bulk modification (multiple SetCoins + one SetBestBlock).
+ // Do a bulk modification (multiple CCoins changes + BestBlock change).
// The passed mapCoins can be modified.
virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
@@ -311,22 +333,41 @@ protected:
CCoinsView *base;
public:
- CCoinsViewBacked(CCoinsView &viewIn);
+ CCoinsViewBacked(CCoinsView *viewIn);
bool GetCoins(const uint256 &txid, CCoins &coins) const;
- bool SetCoins(const uint256 &txid, const CCoins &coins);
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
- bool SetBestBlock(const uint256 &hashBlock);
void SetBackend(CCoinsView &viewIn);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
bool GetStats(CCoinsStats &stats) const;
};
+class CCoinsViewCache;
+
+/** A reference to a mutable cache entry. Encapsulating it allows us to run
+ * cleanup code after the modification is finished, and keeping track of
+ * concurrent modifications. */
+class CCoinsModifier
+{
+private:
+ CCoinsViewCache& cache;
+ CCoinsMap::iterator it;
+ CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_);
+
+public:
+ CCoins* operator->() { return &it->second.coins; }
+ CCoins& operator*() { return it->second.coins; }
+ ~CCoinsModifier();
+ friend class CCoinsViewCache;
+};
+
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
class CCoinsViewCache : public CCoinsViewBacked
{
protected:
+ /* Whether this cache has an active modifier. */
+ bool hasModifier;
/* Make mutable so that we can "fill the cache" even from Get-methods
declared as "const". */
@@ -334,14 +375,14 @@ protected:
mutable CCoinsMap cacheCoins;
public:
- CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false);
+ CCoinsViewCache(CCoinsView *baseIn);
+ ~CCoinsViewCache();
// Standard CCoinsView methods
bool GetCoins(const uint256 &txid, CCoins &coins) const;
- bool SetCoins(const uint256 &txid, const CCoins &coins);
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
- bool SetBestBlock(const uint256 &hashBlock);
+ void SetBestBlock(const uint256 &hashBlock);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
// Return a pointer to CCoins in the cache, or NULL if not found. This is
@@ -349,8 +390,10 @@ public:
// allowed while accessing the returned pointer.
const CCoins* AccessCoins(const uint256 &txid) const;
- // Return a modifiable reference to a CCoins. Check HaveCoins first.
- CCoins &GetCoins(const uint256 &txid);
+ // Return a modifiable reference to a CCoins. If no entry with the given
+ // txid exists, a new one is created. Simultaneous modifications are not
+ // allowed.
+ CCoinsModifier ModifyCoins(const uint256 &txid);
// Push the modifications applied to this cache to its base.
// Failure to call this method before destruction will cause the changes to be forgotten.
@@ -377,6 +420,8 @@ public:
const CTxOut &GetOutputFor(const CTxIn& input) const;
+ friend class CCoinsModifier;
+
private:
CCoinsMap::iterator FetchCoins(const uint256 &txid);
CCoinsMap::const_iterator FetchCoins(const uint256 &txid) const;
diff --git a/src/init.cpp b/src/init.cpp
index 980c589b29..8dcd35fb8f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -237,7 +237,7 @@ std::string HelpMessage(HelpMessageMode mode)
#if !defined(WIN32)
strUsage += " -sysperms " + _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)") + "\n";
#endif
- strUsage += " -txindex " + _("Maintain a full transaction index (default: 0)") + "\n";
+ strUsage += " -txindex " + _("Maintain a full transaction index, used by the getrawtransaction rpc call (default: 0)") + "\n";
strUsage += "\n" + _("Connection options:") + "\n";
strUsage += " -addnode=<ip> " + _("Add a node to connect to and attempt to keep the connection open") + "\n";
@@ -260,7 +260,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n";
strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS5 proxy") + "\n";
strUsage += " -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n";
- strUsage += " -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n";
+ strUsage += " -timeout=<n> " + strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT) + "\n";
#ifdef USE_UPNP
#if USE_UPNP
strUsage += " -upnp " + _("Use UPnP to map the listening port (default: 1 when listening)") + "\n";
@@ -280,7 +280,6 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -mintxfee=<amt> " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)"), FormatMoney(CWallet::minTxFee.GetFeePerK())) + "\n";
strUsage += " -paytxfee=<amt> " + strprintf(_("Fee (in BTC/kB) to add to transactions you send (default: %s)"), FormatMoney(payTxFee.GetFeePerK())) + "\n";
strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + " " + _("on startup") + "\n";
- strUsage += " -respendnotify=<cmd> " + _("Execute command when a network tx respends wallet tx input (%s=respend TxID, %t=wallet TxID)") + "\n";
strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup") + "\n";
strUsage += " -spendzeroconfchange " + _("Spend unconfirmed change when sending transactions (default: 1)") + "\n";
strUsage += " -txconfirmtarget=<n> " + _("If paytxfee is not set, include enough fee so transactions are confirmed on average within n blocks (default: 1)") + "\n";
@@ -641,12 +640,9 @@ bool AppInit2(boost::thread_group& threadGroup)
bool fDisableWallet = GetBoolArg("-disablewallet", false);
#endif
- if (mapArgs.count("-timeout"))
- {
- int nNewTimeout = GetArg("-timeout", 5000);
- if (nNewTimeout > 0 && nNewTimeout < 600000)
- nConnectTimeout = nNewTimeout;
- }
+ nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
+ if (nConnectTimeout <= 0)
+ nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
// Continue to put "/P2SH/" in the coinbase to monitor
// BIP16 support.
@@ -959,7 +955,7 @@ bool AppInit2(boost::thread_group& threadGroup)
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
- pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
+ pcoinsTip = new CCoinsViewCache(pcoinsdbview);
if (fReindex)
pblocktree->WriteReindexing(true);
diff --git a/src/main.cpp b/src/main.cpp
index a3e36ff872..fc8167e40e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -26,8 +26,8 @@
#include <boost/filesystem/fstream.hpp>
#include <boost/thread.hpp>
-using namespace std;
using namespace boost;
+using namespace std;
#if defined(NDEBUG)
# error "Bitcoin cannot be compiled without assertions."
@@ -645,7 +645,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
// IsStandard() will have already returned false
// and this method isn't called.
vector<vector<unsigned char> > stack;
- if (!EvalScript(stack, tx.vin[i].scriptSig, tx, i, false))
+ if (!EvalScript(stack, tx.vin[i].scriptSig, false, BaseSignatureChecker()))
return false;
if (whichType == TX_SCRIPTHASH)
@@ -844,12 +844,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
{
CCoinsView dummy;
- CCoinsViewCache view(dummy);
+ CCoinsViewCache view(&dummy);
CAmount nValueIn = 0;
{
LOCK(pool.cs);
- CCoinsViewMemPool viewMemPool(*pcoinsTip, pool);
+ CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
view.SetBackend(viewMemPool);
// do we already have it?
@@ -943,7 +943,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS))
+ if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true))
{
return error("AcceptToMemoryPool: : ConnectInputs failed %s", hash.ToString());
}
@@ -1178,14 +1178,9 @@ void CheckForkWarningConditions()
{
if (!fLargeWorkForkFound)
{
- std::string strCmd = GetArg("-alertnotify", "");
- if (!strCmd.empty())
- {
- std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
- pindexBestForkBase->phashBlock->ToString() + std::string("'");
- boost::replace_all(strCmd, "%s", warning);
- boost::thread t(runCommand, strCmd); // thread runs free
- }
+ std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
+ pindexBestForkBase->phashBlock->ToString() + std::string("'");
+ CAlert::Notify(warning, true);
}
if (pindexBestForkTip)
{
@@ -1296,32 +1291,28 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight)
{
- bool ret;
// mark inputs spent
if (!tx.IsCoinBase()) {
txundo.vprevout.reserve(tx.vin.size());
- for (unsigned int i = 0; i < tx.vin.size(); i++) {
- const CTxIn &txin = tx.vin[i];
- CCoins &coins = inputs.GetCoins(txin.prevout.hash);
+ BOOST_FOREACH(const CTxIn &txin, tx.vin) {
txundo.vprevout.push_back(CTxInUndo());
- ret = coins.Spend(txin.prevout, txundo.vprevout.back());
+ bool ret = inputs.ModifyCoins(txin.prevout.hash)->Spend(txin.prevout, txundo.vprevout.back());
assert(ret);
}
}
// add outputs
- ret = inputs.SetCoins(tx.GetHash(), CCoins(tx, nHeight));
- assert(ret);
+ inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight);
}
bool CScriptCheck::operator()() const {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
- if (!VerifyScript(scriptSig, scriptPubKey, *ptxTo, nIn, nFlags))
+ if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingSignatureChecker(*ptxTo, nIn, cacheStore)))
return error("CScriptCheck() : %s:%d VerifySignature failed", ptxTo->GetHash().ToString(), nIn);
return true;
}
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
{
@@ -1390,7 +1381,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
assert(coins);
// Verify signature
- CScriptCheck check(*coins, tx, i, flags);
+ CScriptCheck check(*coins, tx, i, flags, cacheStore);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@@ -1403,7 +1394,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// avoid splitting the network between upgraded and
// non-upgraded nodes.
CScriptCheck check(*coins, tx, i,
- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS);
+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
if (check())
return state.Invalid(false, REJECT_NONSTANDARD, "non-mandatory-script-verify-flag");
}
@@ -1453,21 +1444,23 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
// exactly. Note that transactions with only provably unspendable outputs won't
// have outputs available even in the block itself, so we handle that case
// specially with outsEmpty.
+ {
CCoins outsEmpty;
- CCoins &outs = view.HaveCoins(hash) ? view.GetCoins(hash) : outsEmpty;
- outs.ClearUnspendable();
+ CCoinsModifier outs = view.ModifyCoins(hash);
+ outs->ClearUnspendable();
- CCoins outsBlock = CCoins(tx, pindex->nHeight);
+ 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)
+ outs->nVersion = outsBlock.nVersion;
+ if (*outs != outsBlock)
fClean = fClean && error("DisconnectBlock() : added transaction mismatch? database corrupted");
// remove outputs
- outs = CCoins();
+ outs->Clear();
+ }
// restore inputs
if (i > 0) { // not coinbases
@@ -1477,27 +1470,24 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
for (unsigned int j = tx.vin.size(); j-- > 0;) {
const COutPoint &out = tx.vin[j].prevout;
const CTxInUndo &undo = txundo.vprevout[j];
- CCoins coins;
- view.GetCoins(out.hash, coins); // this can fail if the prevout was already entirely spent
+ 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())
+ if (!coins->IsPruned())
fClean = fClean && error("DisconnectBlock() : undo data overwriting existing transaction");
- coins = CCoins();
- coins.fCoinBase = undo.fCoinBase;
- coins.nHeight = undo.nHeight;
- coins.nVersion = undo.nVersion;
+ coins->Clear();
+ coins->fCoinBase = undo.fCoinBase;
+ coins->nHeight = undo.nHeight;
+ coins->nVersion = undo.nVersion;
} else {
- if (coins.IsPruned())
+ if (coins->IsPruned())
fClean = fClean && error("DisconnectBlock() : undo data adding output to missing transaction");
}
- if (coins.IsAvailable(out.n))
+ if (coins->IsAvailable(out.n))
fClean = fClean && error("DisconnectBlock() : undo data overwriting existing output");
- if (coins.vout.size() < out.n+1)
- coins.vout.resize(out.n+1);
- coins.vout[out.n] = undo.txout;
- if (!view.SetCoins(out.hash, coins))
- return error("DisconnectBlock() : cannot restore coin inputs");
+ if (coins->vout.size() < out.n+1)
+ coins->vout.resize(out.n+1);
+ coins->vout[out.n] = undo.txout;
}
}
}
@@ -1599,8 +1589,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
int64_t nBIP16SwitchTime = 1333238400;
bool fStrictPayToScriptHash = (pindex->GetBlockTime() >= nBIP16SwitchTime);
- unsigned int flags = SCRIPT_VERIFY_NOCACHE |
- (fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE);
+ unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
CBlockUndo blockundo;
@@ -1644,7 +1633,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
nFees += view.GetValueIn(tx)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks;
- if (!CheckInputs(tx, state, view, fScriptChecks, flags, nScriptCheckThreads ? &vChecks : NULL))
+ if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL))
return false;
control.Add(vChecks);
}
@@ -1688,7 +1677,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
return error("ConnectBlock() : FindUndoPos failed");
if (!blockundo.WriteToDisk(pos, pindex->pprev->GetBlockHash()))
- return state.Abort(_("Failed to write undo data"));
+ return state.Abort("Failed to write undo data");
// update nUndoPos in block index
pindex->nUndoPos = pos.nPos;
@@ -1699,17 +1688,15 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
CDiskBlockIndex blockindex(pindex);
if (!pblocktree->WriteBlockIndex(blockindex))
- return state.Abort(_("Failed to write block index"));
+ return state.Abort("Failed to write block index");
}
if (fTxIndex)
if (!pblocktree->WriteTxIndex(vPos))
- return state.Abort(_("Failed to write transaction index"));
+ return state.Abort("Failed to write transaction index");
// add this block to the view's block chain
- bool ret;
- ret = view.SetBestBlock(pindex->GetBlockHash());
- assert(ret);
+ view.SetBestBlock(pindex->GetBlockHash());
int64_t nTime3 = GetTimeMicros(); nTimeIndex += nTime3 - nTime2;
LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeIndex * 0.000001);
@@ -1739,7 +1726,7 @@ bool static WriteChainState(CValidationState &state) {
FlushBlockFile();
pblocktree->Sync();
if (!pcoinsTip->Flush())
- return state.Abort(_("Failed to write to coin database"));
+ return state.Abort("Failed to write to coin database");
nLastWrite = GetTimeMicros();
}
return true;
@@ -1753,15 +1740,16 @@ void static UpdateTip(CBlockIndex *pindexNew) {
nTimeBestReceived = GetTime();
mempool.AddTransactionsUpdated(1);
- LogPrintf("UpdateTip: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f\n",
+ LogPrintf("UpdateTip: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u\n",
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(chainActive.Tip()));
+ Checkpoints::GuessVerificationProgress(chainActive.Tip()), (unsigned int)pcoinsTip->GetCacheSize());
cvBlockChange.notify_all();
// Check the version of the last 100 blocks to see if we need to upgrade:
- if (!IsInitialBlockDownload())
+ static bool fWarned = false;
+ if (!IsInitialBlockDownload() && !fWarned)
{
int nUpgraded = 0;
const CBlockIndex* pindex = chainActive.Tip();
@@ -1774,8 +1762,12 @@ void static UpdateTip(CBlockIndex *pindexNew) {
if (nUpgraded > 0)
LogPrintf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, (int)CBlock::CURRENT_VERSION);
if (nUpgraded > 100/2)
+ {
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
strMiscWarning = _("Warning: This version is obsolete, upgrade required!");
+ CAlert::Notify(strMiscWarning, true);
+ fWarned = true;
+ }
}
}
@@ -1787,11 +1779,11 @@ bool static DisconnectTip(CValidationState &state) {
// Read block from disk.
CBlock block;
if (!ReadBlockFromDisk(block, pindexDelete))
- return state.Abort(_("Failed to read block"));
+ return state.Abort("Failed to read block");
// Apply the block atomically to the chain state.
int64_t nStart = GetTimeMicros();
{
- CCoinsViewCache view(*pcoinsTip, true);
+ CCoinsViewCache view(pcoinsTip);
if (!DisconnectBlock(block, state, pindexDelete, view))
return error("DisconnectTip() : DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
assert(view.Flush());
@@ -1836,7 +1828,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
CBlock block;
if (!pblock) {
if (!ReadBlockFromDisk(block, pindexNew))
- return state.Abort(_("Failed to read block"));
+ return state.Abort("Failed to read block");
pblock = &block;
}
// Apply the block atomically to the chain state.
@@ -1844,7 +1836,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
int64_t nTime3;
LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);
{
- CCoinsViewCache view(*pcoinsTip, true);
+ CCoinsViewCache view(pcoinsTip);
CInv inv(MSG_BLOCK, pindexNew->GetBlockHash());
if (!ConnectBlock(*pblock, state, pindexNew, view)) {
if (state.IsInvalid())
@@ -1990,7 +1982,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
CheckForkWarningConditions();
if (!pblocktree->Flush())
- return state.Abort(_("Failed to sync block index"));
+ return state.Abort("Failed to sync block index");
return true;
}
@@ -2027,10 +2019,10 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
// Relay inventory, but don't relay old inventory during initial block download.
int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
{
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
- pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip));
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
+ pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip));
}
uiInterface.NotifyBlockTip(hashNewTip);
@@ -2097,7 +2089,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
setBlockIndexValid.insert(pindexNew);
if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew)))
- return state.Abort(_("Failed to write block index"));
+ return state.Abort("Failed to write block index");
return true;
}
@@ -2149,7 +2141,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd
}
if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile))
- return state.Abort(_("Failed to write file info"));
+ return state.Abort("Failed to write file info");
if (fUpdatedLast)
pblocktree->WriteLastBlockFile(nLastBlockFile);
@@ -2167,15 +2159,15 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
pos.nPos = infoLastBlockFile.nUndoSize;
nNewSize = (infoLastBlockFile.nUndoSize += nAddSize);
if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile))
- return state.Abort(_("Failed to write block info"));
+ return state.Abort("Failed to write block info");
} else {
CBlockFileInfo info;
if (!pblocktree->ReadBlockFileInfo(nFile, info))
- return state.Abort(_("Failed to read block info"));
+ return state.Abort("Failed to read block info");
pos.nPos = info.nUndoSize;
nNewSize = (info.nUndoSize += nAddSize);
if (!pblocktree->WriteBlockFileInfo(nFile, info))
- return state.Abort(_("Failed to write block info"));
+ return state.Abort("Failed to write block info");
}
unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE;
@@ -2274,7 +2266,7 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex
if (miSelf != mapBlockIndex.end()) {
pindex = miSelf->second;
if (pindex->nStatus & BLOCK_FAILED_MASK)
- return state.Invalid(error("AcceptBlock() : block is marked invalid"), 0, "duplicate");
+ return state.Invalid(error("%s : block is marked invalid", __func__), 0, "duplicate");
}
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint();
@@ -2284,12 +2276,12 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex
int64_t deltaTime = block.GetBlockTime() - pcheckpoint->GetBlockTime();
if (deltaTime < 0)
{
- return state.DoS(100, error("CheckBlockHeader() : block with timestamp before last checkpoint"),
+ return state.DoS(100, error("%s : block with timestamp before last checkpoint", __func__),
REJECT_CHECKPOINT, "time-too-old");
}
if (!CheckMinWork(block.nBits, pcheckpoint->nBits, deltaTime))
{
- return state.DoS(100, error("CheckBlockHeader() : block with too little proof-of-work"),
+ return state.DoS(100, error("%s : block with too little proof-of-work", __func__),
REJECT_INVALID, "bad-diffbits");
}
}
@@ -2300,35 +2292,36 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex
if (hash != Params().HashGenesisBlock()) {
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end())
- return state.DoS(10, error("AcceptBlock() : prev block not found"), 0, "bad-prevblk");
+ return state.DoS(10, error("%s : prev block not found", __func__), 0, "bad-prevblk");
pindexPrev = (*mi).second;
nHeight = pindexPrev->nHeight+1;
// Check proof of work
- if (block.nBits != GetNextWorkRequired(pindexPrev, &block))
- return state.DoS(100, error("AcceptBlock() : incorrect proof of work"),
+ if ((!Params().SkipProofOfWorkCheck()) &&
+ (block.nBits != GetNextWorkRequired(pindexPrev, &block)))
+ return state.DoS(100, error("%s : incorrect proof of work", __func__),
REJECT_INVALID, "bad-diffbits");
// Check timestamp against prev
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
- return state.Invalid(error("AcceptBlock() : block's timestamp is too early"),
+ return state.Invalid(error("%s : block's timestamp is too early", __func__),
REJECT_INVALID, "time-too-old");
// Check that the block chain matches the known block chain up to a checkpoint
if (!Checkpoints::CheckBlock(nHeight, hash))
- return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight),
+ return state.DoS(100, error("%s : rejected by checkpoint lock-in at %d", __func__, nHeight),
REJECT_CHECKPOINT, "checkpoint mismatch");
// Don't accept any forks from the main chain prior to last checkpoint
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint();
if (pcheckpoint && nHeight < pcheckpoint->nHeight)
- return state.DoS(100, error("AcceptBlock() : forked chain older than last checkpoint (height %d)", nHeight));
+ return state.DoS(100, error("%s : forked chain older than last checkpoint (height %d)", __func__, nHeight));
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
if (block.nVersion < 2 &&
CBlockIndex::IsSuperMajority(2, pindexPrev, Params().RejectBlockOutdatedMajority()))
{
- return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"),
+ return state.Invalid(error("%s : rejected nVersion=1 block", __func__),
REJECT_OBSOLETE, "bad-version");
}
}
@@ -2391,11 +2384,11 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
return error("AcceptBlock() : FindBlockPos failed");
if (dbp == NULL)
if (!WriteBlockToDisk(block, blockPos))
- return state.Abort(_("Failed to write block"));
+ return state.Abort("Failed to write block");
if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
return error("AcceptBlock() : ReceivedBlockTransactions failed");
} catch(std::runtime_error &e) {
- return state.Abort(_("System error: ") + e.what());
+ return state.Abort(std::string("System error: ") + e.what());
}
return true;
@@ -2718,10 +2711,12 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
-bool AbortNode(const std::string &strMessage) {
+bool AbortNode(const std::string &strMessage, const std::string &userMessage) {
strMiscWarning = strMessage;
LogPrintf("*** %s\n", strMessage);
- uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_ERROR);
+ uiInterface.ThreadSafeMessageBox(
+ userMessage.empty() ? _("Error: A fatal internal error occured, see debug.log for details") : userMessage,
+ "", CClientUIInterface::MSG_ERROR);
StartShutdown();
return false;
}
@@ -2732,7 +2727,7 @@ bool CheckDiskSpace(uint64_t nAdditionalBytes)
// Check for nMinDiskSpace bytes (currently 50MB)
if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes)
- return AbortNode(_("Error: Disk space is low!"));
+ return AbortNode("Disk space is low!", _("Error: Disk space is low!"));
return true;
}
@@ -2891,7 +2886,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
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, true);
+ CCoinsViewCache coins(coinsview);
CBlockIndex* pindexState = chainActive.Tip();
CBlockIndex* pindexFailure = NULL;
int nGoodTransactions = 0;
@@ -3084,6 +3079,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
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 nStartByte = 0;
if (dbp) {
@@ -3140,9 +3136,8 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
LogPrintf("%s : Deserialize or I/O error - %s", __func__, e.what());
}
}
- fclose(fileIn);
} catch(std::runtime_error &e) {
- AbortNode(_("Error: system error: ") + e.what());
+ AbortNode(std::string("System error: ") + e.what());
}
if (nLoaded > 0)
LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, GetTimeMillis() - nStart);
diff --git a/src/main.h b/src/main.h
index 7e849505dd..cad7eebfb7 100644
--- a/src/main.h
+++ b/src/main.h
@@ -17,6 +17,7 @@
#include "net.h"
#include "pow.h"
#include "script/script.h"
+#include "script/sigcache.h"
#include "script/standard.h"
#include "sync.h"
#include "txmempool.h"
@@ -177,7 +178,7 @@ CAmount GetBlockValue(int nHeight, const CAmount& nFees);
/** Create a new block index entry for a given block hash */
CBlockIndex * InsertBlockIndex(uint256 hash);
/** Abort with a message */
-bool AbortNode(const std::string &msg);
+bool AbortNode(const std::string &msg, const std::string &userMessage="");
/** Get statistics from node state */
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
/** Increase a node's misbehavior score. */
@@ -258,9 +259,8 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma
// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
// This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
// instead of being performed inline.
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks = true,
- unsigned int flags = STANDARD_SCRIPT_VERIFY_FLAGS,
- std::vector<CScriptCheck> *pvChecks = NULL);
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
+ unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks = NULL);
// Apply the effects of this transaction on the UTXO set represented by view
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight);
@@ -302,12 +302,13 @@ private:
const CTransaction *ptxTo;
unsigned int nIn;
unsigned int nFlags;
+ bool cacheStore;
public:
- CScriptCheck(): ptxTo(0), nIn(0), nFlags(0) {}
- CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn) :
+ CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false) {}
+ CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) :
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey),
- ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn) { }
+ ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn) { }
bool operator()() const;
@@ -316,6 +317,7 @@ public:
std::swap(ptxTo, check.ptxTo);
std::swap(nIn, check.nIn);
std::swap(nFlags, check.nFlags);
+ std::swap(cacheStore, check.cacheStore);
}
};
diff --git a/src/miner.cpp b/src/miner.cpp
index 361a2bea41..c2762bf44e 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -83,6 +83,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
return NULL;
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
+ // -regtest only: allow overriding block.nVersion with
+ // -blockversion=N to test forking scenarios
+ if (Params().MineBlocksOnDemand())
+ pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
+
// Create coinbase tx
CMutableTransaction txNew;
txNew.vin.resize(1);
@@ -116,7 +121,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
{
LOCK2(cs_main, mempool.cs);
CBlockIndex* pindexPrev = chainActive.Tip();
- CCoinsViewCache view(*pcoinsTip, true);
+ CCoinsViewCache view(pcoinsTip);
// Priority order to process transactions
list<COrphan> vOrphan; // list memory doesn't move
@@ -257,7 +262,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
// policy here, but we still have to ensure that the block we
// create only contains transactions that are valid in new blocks.
CValidationState state;
- if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS))
+ if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true))
continue;
CTxUndo txundo;
@@ -316,7 +321,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
CBlockIndex indexDummy(*pblock);
indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1;
- CCoinsViewCache viewNew(*pcoinsTip, true);
+ CCoinsViewCache viewNew(pcoinsTip);
CValidationState state;
if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true))
throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 5819c152a3..b3d1001547 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -40,7 +40,7 @@ using namespace std;
static proxyType proxyInfo[NET_MAX];
static CService nameProxy;
static CCriticalSection cs_proxyInfos;
-int nConnectTimeout = 5000;
+int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
bool fNameLookup = false;
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
diff --git a/src/netbase.h b/src/netbase.h
index 9fc5c72eb8..1455cd8c33 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -19,6 +19,9 @@
extern int nConnectTimeout;
extern bool fNameLookup;
+/** -timeout default */
+static const int DEFAULT_CONNECT_TIMEOUT = 5000;
+
#ifdef WIN32
// In MSVC, this is defined as a macro, undefine it to prevent a compile and link error
#undef SetPort
diff --git a/src/pow.cpp b/src/pow.cpp
index 893f6c18be..d50222849c 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -81,6 +81,10 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits)
bool fNegative;
bool fOverflow;
uint256 bnTarget;
+
+ if (Params().SkipProofOfWorkCheck())
+ return true;
+
bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
// Check range
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 3b4b40aae3..25c811183f 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -195,21 +195,11 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires newer version of Bitcoin Core"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: A fatal internal error occured, see debug.log for details"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unsupported argument -tor found, use -onion."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction!"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Error: system error: "),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Failed to read block info"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Failed to read block"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Failed to sync block index"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block index"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block info"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write file info"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write to coin database"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write transaction index"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write undo data"),
QT_TRANSLATE_NOOP("bitcoin-core", "Fee (in BTC/kB) to add to transactions you send (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Force safe mode (default: 0)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins (default: 0)"),
@@ -231,6 +221,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s'")
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Keep at most <n> unconnectable blocks in memory (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Keep at most <n> unconnectable transactions in memory (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Limit size of signature cache to <n> entries (default: 50000)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on <port> (default: 8333 or testnet: 18333)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."),
@@ -245,7 +236,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Need to specify a port with -whitebind: '%s'"
QT_TRANSLATE_NOOP("bitcoin-core", "Node relay options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."),
QT_TRANSLATE_NOOP("bitcoin-core", "Only accept block chain matching built-in checkpoints (default: 1)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Only connect to nodes in network <net> (IPv4, IPv6 or Tor)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Only connect to nodes in network <net> (ipv4, ipv6 or onion)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp (default: 1)"),
@@ -282,7 +273,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Specify wallet file (within data directory)")
QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Spend unconfirmed change when sending transactions (default: 1)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Stop running after importing blocks from disk (default: 0)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "System error: "),
QT_TRANSLATE_NOOP("bitcoin-core", "This help message"),
QT_TRANSLATE_NOOP("bitcoin-core", "This is experimental software."),
QT_TRANSLATE_NOOP("bitcoin-core", "This is intended for regression testing tools and app development."),
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index a527602b5a..5c3abef2e7 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -19,7 +19,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+11"/>
+ <location line="+14"/>
<source>Copy the currently selected address to the system clipboard</source>
<translation>Copy the currently selected address to the system clipboard</translation>
</message>
@@ -29,7 +29,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+58"/>
+ <location line="+67"/>
<source>C&amp;lose</source>
<translation type="unfinished"></translation>
</message>
@@ -39,12 +39,12 @@
<translation>&amp;Copy Address</translation>
</message>
<message>
- <location filename="../forms/addressbookpage.ui" line="-47"/>
+ <location filename="../forms/addressbookpage.ui" line="-53"/>
<source>Delete the currently selected address from the list</source>
<translation>Delete the currently selected address from the list</translation>
</message>
<message>
- <location line="+27"/>
+ <location line="+30"/>
<source>Export the data in the current tab to a file</source>
<translation>Export the data in the current tab to a file</translation>
</message>
@@ -54,7 +54,7 @@
<translation>&amp;Export</translation>
</message>
<message>
- <location line="-27"/>
+ <location line="-30"/>
<source>&amp;Delete</source>
<translation>&amp;Delete</translation>
</message>
@@ -286,17 +286,17 @@
<context>
<name>BitcoinGUI</name>
<message>
- <location filename="../bitcoingui.cpp" line="+300"/>
+ <location filename="../bitcoingui.cpp" line="+327"/>
<source>Sign &amp;message...</source>
<translation>Sign &amp;message...</translation>
</message>
<message>
- <location line="+339"/>
+ <location line="+348"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
- <location line="-411"/>
+ <location line="-420"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
@@ -377,13 +377,13 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+168"/>
+ <location line="+175"/>
<location line="+5"/>
<source>Bitcoin Core client</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+156"/>
+ <location line="+158"/>
<source>Importing blocks from disk...</source>
<translation>Importing blocks from disk...</translation>
</message>
@@ -393,7 +393,7 @@
<translation>Reindexing blocks on disk...</translation>
</message>
<message>
- <location line="-409"/>
+ <location line="-418"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -428,12 +428,12 @@
<translation>&amp;Verify message...</translation>
</message>
<message>
- <location line="+437"/>
+ <location line="+446"/>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
<message>
- <location line="-655"/>
+ <location line="-664"/>
<source>Wallet</source>
<translation>Wallet</translation>
</message>
@@ -500,12 +500,12 @@
</message>
<message>
<location line="-289"/>
- <location line="+386"/>
+ <location line="+393"/>
<source>[testnet]</source>
<translation>[testnet]</translation>
</message>
<message>
- <location line="-411"/>
+ <location line="-418"/>
<source>Bitcoin Core</source>
<translation type="unfinished">Bitcoin Core</translation>
</message>
@@ -546,7 +546,7 @@
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+310"/>
+ <location line="+316"/>
<source>%n active connection(s) to Bitcoin network</source>
<translation>
<numerusform>%n active connection to Bitcoin network</numerusform>
@@ -554,7 +554,7 @@
</translation>
</message>
<message>
- <location line="+22"/>
+ <location line="+25"/>
<source>No block source available...</source>
<translation>No block source available...</translation>
</message>
@@ -665,7 +665,7 @@ Address: %4
</translation>
</message>
<message>
- <location line="+69"/>
+ <location line="+68"/>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</translation>
</message>
@@ -678,7 +678,7 @@ Address: %4
<context>
<name>ClientModel</name>
<message>
- <location filename="../clientmodel.cpp" line="+138"/>
+ <location filename="../clientmodel.cpp" line="+139"/>
<source>Network Alert</source>
<translation>Network Alert</translation>
</message>
@@ -736,7 +736,7 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
+ <location line="+16"/>
<source>Tree mode</source>
<translation type="unfinished"></translation>
</message>
@@ -1059,7 +1059,7 @@ Address: %4
<context>
<name>HelpMessageDialog</name>
<message>
- <location filename="../utilitydialog.cpp" line="+29"/>
+ <location filename="../utilitydialog.cpp" line="+31"/>
<source>Bitcoin Core</source>
<translation type="unfinished">Bitcoin Core</translation>
</message>
@@ -1201,7 +1201,7 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+11"/>
+ <location line="+10"/>
<source>Select payment request file</source>
<translation type="unfinished"></translation>
</message>
@@ -1430,12 +1430,12 @@ Address: %4
<translation>&amp;OK</translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+13"/>
<source>&amp;Cancel</source>
<translation>&amp;Cancel</translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="+68"/>
+ <location filename="../optionsdialog.cpp" line="+71"/>
<source>default</source>
<translation>default</translation>
</message>
@@ -1479,23 +1479,18 @@ Address: %4
<translation>Form</translation>
</message>
<message>
- <location line="+52"/>
- <location line="+394"/>
+ <location line="+53"/>
+ <location line="+372"/>
<source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source>
<translation>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</translation>
</message>
<message>
- <location line="-401"/>
- <source>Wallet</source>
- <translation>Wallet</translation>
- </message>
- <message>
- <location line="+33"/>
+ <location line="-133"/>
<source>Watch-only:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+43"/>
+ <location line="+10"/>
<source>Available:</source>
<translation type="unfinished"></translation>
</message>
@@ -1505,62 +1500,72 @@ Address: %4
<translation>Your current spendable balance</translation>
</message>
<message>
- <location line="+16"/>
+ <location line="+41"/>
<source>Pending:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+16"/>
+ <location line="-236"/>
<source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
<translation>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</translation>
</message>
<message>
- <location line="+16"/>
+ <location line="+112"/>
<source>Immature:</source>
<translation>Immature:</translation>
</message>
<message>
- <location line="+16"/>
+ <location line="-29"/>
<source>Mined balance that has not yet matured</source>
<translation>Mined balance that has not yet matured</translation>
</message>
<message>
- <location line="+23"/>
+ <location line="-163"/>
+ <source>Balances</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+147"/>
<source>Total:</source>
<translation>Total:</translation>
</message>
<message>
- <location line="+16"/>
+ <location line="+61"/>
<source>Your current total balance</source>
<translation>Your current total balance</translation>
</message>
<message>
- <location line="+38"/>
+ <location line="+92"/>
<source>Your current balance in watch-only addresses</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+25"/>
+ <location line="+23"/>
+ <source>Spendable:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+49"/>
+ <source>Recent transactions</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-317"/>
<source>Unconfirmed transactions to watch-only addresses</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+25"/>
+ <location line="+50"/>
<source>Mined balance in watch-only addresses that has not yet matured</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+44"/>
+ <location line="+128"/>
<source>Current total balance in watch-only addresses</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+67"/>
- <source>&lt;b&gt;Recent transactions&lt;/b&gt;</source>
- <translation>&lt;b&gt;Recent transactions&lt;/b&gt;</translation>
- </message>
- <message>
- <location filename="../overviewpage.cpp" line="+123"/>
+ <location filename="../overviewpage.cpp" line="+131"/>
<location line="+1"/>
<source>out of sync</source>
<translation>out of sync</translation>
@@ -1569,7 +1574,7 @@ Address: %4
<context>
<name>PaymentServer</name>
<message>
- <location filename="../paymentserver.cpp" line="+405"/>
+ <location filename="../paymentserver.cpp" line="+410"/>
<location line="+14"/>
<location line="+7"/>
<source>URI handling</source>
@@ -1681,7 +1686,7 @@ Address: %4
<context>
<name>PeerTableModel</name>
<message>
- <location filename="../peertablemodel.cpp" line="+112"/>
+ <location filename="../peertablemodel.cpp" line="+118"/>
<source>User Agent</source>
<translation type="unfinished"></translation>
</message>
@@ -1699,17 +1704,17 @@ Address: %4
<context>
<name>QObject</name>
<message>
- <location filename="../bitcoinunits.cpp" line="+200"/>
+ <location filename="../bitcoinunits.cpp" line="+196"/>
<source>Amount</source>
<translation type="unfinished">Amount</translation>
</message>
<message>
- <location filename="../guiutil.cpp" line="+97"/>
+ <location filename="../guiutil.cpp" line="+106"/>
<source>Enter a Bitcoin address (e.g. %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+673"/>
+ <location line="+698"/>
<source>%1 d</source>
<translation type="unfinished"></translation>
</message>
@@ -1795,7 +1800,7 @@ Address: %4
<location line="+23"/>
<location line="+36"/>
<location line="+23"/>
- <location line="+462"/>
+ <location line="+465"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
@@ -1813,7 +1818,7 @@ Address: %4
<translation>N/A</translation>
</message>
<message>
- <location line="-987"/>
+ <location line="-990"/>
<source>Client version</source>
<translation>Client version</translation>
</message>
@@ -1873,7 +1878,7 @@ Address: %4
<translation>Current number of blocks</translation>
</message>
<message>
- <location line="+300"/>
+ <location line="+303"/>
<source>Received</source>
<translation type="unfinished"></translation>
</message>
@@ -1889,7 +1894,7 @@ Address: %4
</message>
<message>
<location line="+39"/>
- <location filename="../rpcconsole.cpp" line="+234"/>
+ <location filename="../rpcconsole.cpp" line="+236"/>
<location line="+327"/>
<source>Select a peer to view detailed information.</source>
<translation type="unfinished"></translation>
@@ -1965,7 +1970,7 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-761"/>
+ <location line="-764"/>
<source>Last block time</source>
<translation>Last block time</translation>
</message>
@@ -1990,7 +1995,7 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
+ <location line="+16"/>
<source>Totals</source>
<translation type="unfinished"></translation>
</message>
@@ -2005,7 +2010,7 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../forms/rpcconsole.ui" line="-354"/>
+ <location filename="../forms/rpcconsole.ui" line="-357"/>
<source>Build date</source>
<translation>Build date</translation>
</message>
@@ -2163,12 +2168,12 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+78"/>
+ <location line="+75"/>
<source>Requested payments history</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-98"/>
+ <location line="-95"/>
<source>&amp;Request payment</source>
<translation type="unfinished"></translation>
</message>
@@ -2183,7 +2188,7 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+17"/>
<source>Remove the selected entries from the list</source>
<translation type="unfinished"></translation>
</message>
@@ -2221,12 +2226,12 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+10"/>
<source>Copy &amp;Address</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+10"/>
<source>&amp;Save Image...</source>
<translation type="unfinished"></translation>
</message>
@@ -2279,7 +2284,7 @@ Address: %4
<context>
<name>RecentRequestsTableModel</name>
<message>
- <location filename="../recentrequeststablemodel.cpp" line="+24"/>
+ <location filename="../recentrequeststablemodel.cpp" line="+26"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -2333,7 +2338,7 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+10"/>
<source>automatically selected</source>
<translation type="unfinished"></translation>
</message>
@@ -2398,22 +2403,22 @@ Address: %4
<translation>Add &amp;Recipient</translation>
</message>
<message>
- <location line="-23"/>
+ <location line="-20"/>
<source>Clear all fields of the form.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-271"/>
+ <location line="-274"/>
<source>Dust:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+274"/>
+ <location line="+277"/>
<source>Clear &amp;All</source>
<translation>Clear &amp;All</translation>
</message>
<message>
- <location line="+58"/>
+ <location line="+55"/>
<source>Balance:</source>
<translation>Balance:</translation>
</message>
@@ -2653,7 +2658,7 @@ Address: %4
<context>
<name>ShutdownWindow</name>
<message>
- <location filename="../utilitydialog.cpp" line="+51"/>
+ <location filename="../utilitydialog.cpp" line="+47"/>
<source>Bitcoin Core is shutting down...</source>
<translation type="unfinished"></translation>
</message>
@@ -2671,7 +2676,7 @@ Address: %4
<translation>Signatures - Sign / Verify a Message</translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+13"/>
<source>&amp;Sign Message</source>
<translation>&amp;Sign Message</translation>
</message>
@@ -2848,7 +2853,7 @@ Address: %4
<context>
<name>SplashScreen</name>
<message>
- <location filename="../splashscreen.cpp" line="+32"/>
+ <location filename="../splashscreen.cpp" line="+34"/>
<source>Bitcoin Core</source>
<translation type="unfinished">Bitcoin Core</translation>
</message>
@@ -2874,7 +2879,7 @@ Address: %4
<context>
<name>TransactionDesc</name>
<message>
- <location filename="../transactiondesc.cpp" line="+33"/>
+ <location filename="../transactiondesc.cpp" line="+34"/>
<source>Open until %1</source>
<translation>Open until %1</translation>
</message>
@@ -3098,7 +3103,7 @@ Address: %4
<context>
<name>TransactionTableModel</name>
<message>
- <location filename="../transactiontablemodel.cpp" line="+237"/>
+ <location filename="../transactiontablemodel.cpp" line="+235"/>
<source>Date</source>
<translation>Date</translation>
</message>
@@ -3166,7 +3171,7 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+51"/>
+ <location line="+48"/>
<source>Received with</source>
<translation>Received with</translation>
</message>
@@ -3191,12 +3196,17 @@ Address: %4
<translation>Mined</translation>
</message>
<message>
- <location line="+41"/>
+ <location line="+28"/>
+ <source>watch-only</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+15"/>
<source>(n/a)</source>
<translation>(n/a)</translation>
</message>
<message>
- <location line="+193"/>
+ <location line="+210"/>
<source>Transaction status. Hover over this field to show number of confirmations.</source>
<translation>Transaction status. Hover over this field to show number of confirmations.</translation>
</message>
@@ -3212,6 +3222,11 @@ Address: %4
</message>
<message>
<location line="+2"/>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
<source>Destination address of transaction.</source>
<translation>Destination address of transaction.</translation>
</message>
@@ -3224,7 +3239,7 @@ Address: %4
<context>
<name>TransactionView</name>
<message>
- <location filename="../transactionview.cpp" line="+60"/>
+ <location filename="../transactionview.cpp" line="+67"/>
<location line="+16"/>
<source>All</source>
<translation>All</translation>
@@ -3325,12 +3340,17 @@ Address: %4
<translation>Show transaction details</translation>
</message>
<message>
- <location line="+163"/>
+ <location line="+179"/>
<source>Export Transaction History</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+19"/>
+ <location line="+12"/>
+ <source>Watch-only</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
<source>Exporting Failed</source>
<translation type="unfinished"></translation>
</message>
@@ -3350,7 +3370,7 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-22"/>
+ <location line="-24"/>
<source>Comma separated file (*.csv)</source>
<translation>Comma separated file (*.csv)</translation>
</message>
@@ -3360,7 +3380,7 @@ Address: %4
<translation>Confirmed</translation>
</message>
<message>
- <location line="+1"/>
+ <location line="+3"/>
<source>Date</source>
<translation>Date</translation>
</message>
@@ -3398,7 +3418,7 @@ Address: %4
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
- <location filename="../bitcoingui.cpp" line="+101"/>
+ <location filename="../bitcoingui.cpp" line="+103"/>
<source>Unit to show amounts in. Click to select another unit.</source>
<translation type="unfinished"></translation>
</message>
@@ -3465,7 +3485,7 @@ Address: %4
<context>
<name>bitcoin-core</name>
<message>
- <location filename="../bitcoinstrings.cpp" line="+249"/>
+ <location filename="../bitcoinstrings.cpp" line="+240"/>
<source>Options:</source>
<translation>Options:</translation>
</message>
@@ -3495,22 +3515,22 @@ Address: %4
<translation>Maintain at most &lt;n&gt; connections to peers (default: 125)</translation>
</message>
<message>
- <location line="-62"/>
+ <location line="-53"/>
<source>Connect to a node to retrieve peer addresses, and disconnect</source>
<translation>Connect to a node to retrieve peer addresses, and disconnect</translation>
</message>
<message>
- <location line="+103"/>
+ <location line="+94"/>
<source>Specify your own public address</source>
<translation>Specify your own public address</translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+6"/>
<source>Threshold for disconnecting misbehaving peers (default: 100)</source>
<translation>Threshold for disconnecting misbehaving peers (default: 100)</translation>
</message>
<message>
- <location line="-181"/>
+ <location line="-171"/>
<source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source>
<translation>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</translation>
</message>
@@ -3525,17 +3545,17 @@ Address: %4
<translation>Accept command line and JSON-RPC commands</translation>
</message>
<message>
- <location line="+99"/>
+ <location line="+90"/>
<source>Run in the background as a daemon and accept commands</source>
<translation>Run in the background as a daemon and accept commands</translation>
</message>
<message>
- <location line="+36"/>
+ <location line="+35"/>
<source>Use the test network</source>
<translation>Use the test network</translation>
</message>
<message>
- <location line="-134"/>
+ <location line="-124"/>
<source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
<translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation>
</message>
@@ -3756,6 +3776,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<location line="+2"/>
+ <source>Error: A fatal internal error occured, see debug.log for details</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Error: Disk space is low!</source>
<translation>Error: Disk space is low!</translation>
</message>
@@ -3766,65 +3791,10 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<location line="+1"/>
- <source>Error: system error: </source>
- <translation>Error: system error: </translation>
- </message>
- <message>
- <location line="+1"/>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation>Failed to listen on any port. Use -listen=0 if you want this.</translation>
</message>
<message>
- <location line="+1"/>
- <source>Failed to read block info</source>
- <translation>Failed to read block info</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Failed to read block</source>
- <translation>Failed to read block</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Failed to sync block index</source>
- <translation>Failed to sync block index</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Failed to write block index</source>
- <translation>Failed to write block index</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Failed to write block info</source>
- <translation>Failed to write block info</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Failed to write block</source>
- <translation>Failed to write block</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Failed to write file info</source>
- <translation>Failed to write file info</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Failed to write to coin database</source>
- <translation>Failed to write to coin database</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Failed to write transaction index</source>
- <translation>Failed to write transaction index</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Failed to write undo data</source>
- <translation>Failed to write undo data</translation>
- </message>
- <message>
<location line="+2"/>
<source>Force safe mode (default: 0)</source>
<translation type="unfinished"></translation>
@@ -3860,12 +3830,17 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+21"/>
+ <location line="+22"/>
<source>Not enough file descriptors available.</source>
<translation>Not enough file descriptors available.</translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+2"/>
+ <source>Only connect to nodes in network &lt;net&gt; (ipv4, ipv6 or onion)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Prepend debug output with timestamp (default: 1)</source>
<translation type="unfinished"></translation>
</message>
@@ -3905,7 +3880,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+3"/>
<source>This is intended for regression testing tools and app development.</source>
<translation type="unfinished"></translation>
</message>
@@ -3940,7 +3915,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Imports blocks from external blk000??.dat file</translation>
</message>
<message>
- <location line="-195"/>
+ <location line="-185"/>
<source>(default: 1, 1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source>
<translation type="unfinished"></translation>
</message>
@@ -4080,12 +4055,12 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+5"/>
<source>Error: Unsupported argument -tor found, use -onion.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+3"/>
<source>Fee (in BTC/kB) to add to transactions you send (default: %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -4131,6 +4106,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<location line="+1"/>
+ <source>Keep at most &lt;n&gt; unconnectable transactions in memory (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Limit size of signature cache to &lt;n&gt; entries (default: 50000)</source>
<translation type="unfinished"></translation>
</message>
@@ -4170,12 +4150,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Only accept block chain matching built-in checkpoints (default: 1)</translation>
</message>
<message>
- <location line="+1"/>
- <source>Only connect to nodes in network &lt;net&gt; (IPv4, IPv6 or Tor)</source>
- <translation>Only connect to nodes in network &lt;net&gt; (IPv4, IPv6 or Tor)</translation>
- </message>
- <message>
- <location line="+4"/>
+ <location line="+5"/>
<source>Print block on startup, if found in block index</source>
<translation type="unfinished"></translation>
</message>
@@ -4255,12 +4230,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Specify connection timeout in milliseconds (default: 5000)</translation>
</message>
<message>
- <location line="+7"/>
- <source>System error: </source>
- <translation>System error: </translation>
- </message>
- <message>
- <location line="+2"/>
+ <location line="+8"/>
<source>This is experimental software.</source>
<translation type="unfinished"></translation>
</message>
@@ -4340,22 +4310,22 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>wallet.dat corrupt, salvage failed</translation>
</message>
<message>
- <location line="-64"/>
+ <location line="-63"/>
<source>Password for JSON-RPC connections</source>
<translation>Password for JSON-RPC connections</translation>
</message>
<message>
- <location line="-164"/>
+ <location line="-155"/>
<source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
<translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation>
</message>
<message>
- <location line="+210"/>
+ <location line="+200"/>
<source>Upgrade wallet to latest format</source>
<translation>Upgrade wallet to latest format</translation>
</message>
<message>
- <location line="-27"/>
+ <location line="-26"/>
<source>Set key pool size to &lt;n&gt; (default: 100)</source>
<translation>Set key pool size to &lt;n&gt; (default: 100)</translation>
</message>
@@ -4365,12 +4335,12 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Rescan the block chain for missing wallet transactions</translation>
</message>
<message>
- <location line="+36"/>
+ <location line="+35"/>
<source>Use OpenSSL (https) for JSON-RPC connections</source>
<translation>Use OpenSSL (https) for JSON-RPC connections</translation>
</message>
<message>
- <location line="-31"/>
+ <location line="-30"/>
<source>Server certificate file (default: server.cert)</source>
<translation>Server certificate file (default: server.cert)</translation>
</message>
@@ -4380,22 +4350,22 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Server private key (default: server.pem)</translation>
</message>
<message>
- <location line="+19"/>
+ <location line="+18"/>
<source>This help message</source>
<translation>This help message</translation>
</message>
<message>
- <location line="-118"/>
+ <location line="-108"/>
<source>Allow DNS lookups for -addnode, -seednode and -connect</source>
<translation>Allow DNS lookups for -addnode, -seednode and -connect</translation>
</message>
<message>
- <location line="+68"/>
+ <location line="+59"/>
<source>Loading addresses...</source>
<translation>Loading addresses...</translation>
</message>
<message>
- <location line="-42"/>
+ <location line="-33"/>
<source>Error loading wallet.dat: Wallet corrupted</source>
<translation>Error loading wallet.dat: Wallet corrupted</translation>
</message>
@@ -4405,7 +4375,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Error loading wallet.dat</translation>
</message>
<message>
- <location line="+33"/>
+ <location line="+23"/>
<source>Invalid -proxy address: &apos;%s&apos;</source>
<translation>Invalid -proxy address: &apos;%s&apos;</translation>
</message>
@@ -4415,7 +4385,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Unknown network specified in -onlynet: &apos;%s&apos;</translation>
</message>
<message>
- <location line="-122"/>
+ <location line="-112"/>
<source>Cannot resolve -bind address: &apos;%s&apos;</source>
<translation>Cannot resolve -bind address: &apos;%s&apos;</translation>
</message>
@@ -4425,7 +4395,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Cannot resolve -externalip address: &apos;%s&apos;</translation>
</message>
<message>
- <location line="+56"/>
+ <location line="+46"/>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos;</source>
<translation>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos;</translation>
</message>
@@ -4440,22 +4410,22 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Insufficient funds</translation>
</message>
<message>
- <location line="+13"/>
+ <location line="+14"/>
<source>Loading block index...</source>
<translation>Loading block index...</translation>
</message>
<message>
- <location line="-70"/>
+ <location line="-61"/>
<source>Add a node to connect to and attempt to keep the connection open</source>
<translation>Add a node to connect to and attempt to keep the connection open</translation>
</message>
<message>
- <location line="+71"/>
+ <location line="+62"/>
<source>Loading wallet...</source>
<translation>Loading wallet...</translation>
</message>
<message>
- <location line="-66"/>
+ <location line="-57"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
@@ -4465,22 +4435,22 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Cannot write default address</translation>
</message>
<message>
- <location line="+86"/>
+ <location line="+77"/>
<source>Rescanning...</source>
<translation>Rescanning...</translation>
</message>
<message>
- <location line="-73"/>
+ <location line="-64"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>
<message>
- <location line="+101"/>
+ <location line="+91"/>
<source>To use the %s option</source>
<translation>To use the %s option</translation>
</message>
<message>
- <location line="-93"/>
+ <location line="-83"/>
<source>Error</source>
<translation>Error</translation>
</message>
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index cb80bd0e3d..6db654dff7 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -119,6 +119,8 @@ void OptionsModel::Init()
// Only try to set -proxy, if user has enabled fUseProxy
if (settings.value("fUseProxy").toBool() && !SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
addOverriddenOption("-proxy");
+ else if(!settings.value("fUseProxy").toBool() && !GetArg("-proxy", "").empty())
+ addOverriddenOption("-proxy");
// Display
if (!settings.contains("language"))
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 4b3beae20c..24175215bf 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -381,7 +381,7 @@ Value gettxout(const Array& params, bool fHelp)
CCoins coins;
if (fMempool) {
LOCK(mempool.cs);
- CCoinsViewMemPool view(*pcoinsTip, mempool);
+ CCoinsViewMemPool view(pcoinsTip, mempool);
if (!view.GetCoins(hash, coins))
return Value::null;
mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index fb159d96f6..bc19d1372a 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -368,23 +368,29 @@ Value getnetworkinfo(const Array& params, bool fHelp)
"Returns an object containing various state info regarding P2P networking.\n"
"\nResult:\n"
"{\n"
- " \"version\": xxxxx, (numeric) the server version\n"
- " \"protocolversion\": xxxxx, (numeric) the protocol version\n"
- " \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n"
- " \"timeoffset\": xxxxx, (numeric) the time offset\n"
- " \"connections\": xxxxx, (numeric) the number of connections\n"
- " \"networks\": [ (array) information per network\n"
- " \"name\": \"xxx\", (string) network (ipv4, ipv6 or onion)\n"
- " \"limited\": xxx, (boolean) is the network limited using -onlynet?\n"
- " \"reachable\": xxx, (boolean) is the network reachable?\n"
- " \"proxy\": \"host:port\" (string) the proxy that is used for this network, or empty if none\n"
- " },\n"
+ " \"version\": xxxxx, (numeric) the server version\n"
+ " \"subversion\": \"/Satoshi:x.x.x/\", (string) the server subversion string\n"
+ " \"protocolversion\": xxxxx, (numeric) the protocol version\n"
+ " \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n"
+ " \"timeoffset\": xxxxx, (numeric) the time offset\n"
+ " \"connections\": xxxxx, (numeric) the number of connections\n"
+ " \"networks\": [ (array) information per network\n"
+ " {\n"
+ " \"name\": \"xxx\", (string) network (ipv4, ipv6 or onion)\n"
+ " \"limited\": true|false, (boolean) is the network limited using -onlynet?\n"
+ " \"reachable\": true|false, (boolean) is the network reachable?\n"
+ " \"proxy\": \"host:port\" (string) the proxy that is used for this network, or empty if none\n"
+ " }\n"
+ " ,...\n"
" ],\n"
- " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n"
- " \"localaddresses\": [, (array) list of local addresses\n"
- " \"address\": \"xxxx\", (string) network address\n"
- " \"port\": xxx, (numeric) network port\n"
- " \"score\": xxx (numeric) relative score\n"
+ " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n"
+ " \"localaddresses\": [ (array) list of local addresses\n"
+ " {\n"
+ " \"address\": \"xxxx\", (string) network address\n"
+ " \"port\": xxx, (numeric) network port\n"
+ " \"score\": xxx (numeric) relative score\n"
+ " }\n"
+ " ,...\n"
" ]\n"
"}\n"
"\nExamples:\n"
@@ -393,10 +399,10 @@ Value getnetworkinfo(const Array& params, bool fHelp)
);
Object obj;
- obj.push_back(Pair("version", (int)CLIENT_VERSION));
+ obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("subversion",
FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>())));
- obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
+ obj.push_back(Pair("protocolversion",PROTOCOL_VERSION));
obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index bd87d77704..78372da685 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -110,6 +110,9 @@ Value getrawtransaction(const Array& params, bool fHelp)
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getrawtransaction \"txid\" ( verbose )\n"
+ "\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n"
+ "or there is an unspent output in the utxo for this transaction. To make it always work,\n"
+ "you need to maintain a transaction index, using the -txindex command line option.\n"
"\nReturn the raw transaction data.\n"
"\nIf verbose=0, returns a string that is serialized, hex-encoded data for 'txid'.\n"
"If verbose is non-zero, returns an Object with information about 'txid'.\n"
@@ -202,7 +205,7 @@ Value listunspent(const Array& params, bool fHelp)
"Results are an array of Objects, each of which has:\n"
"{txid, vout, scriptPubKey, amount, confirmations}\n"
"\nArguments:\n"
- "1. minconf (numeric, optional, default=1) The minimum confirmationsi to filter\n"
+ "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
"2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
"3. \"addresses\" (string) A json array of bitcoin addresses to filter\n"
" [\n"
@@ -557,11 +560,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
// Fetch previous transactions (inputs):
CCoinsView viewDummy;
- CCoinsViewCache view(viewDummy);
+ CCoinsViewCache view(&viewDummy);
{
LOCK(mempool.cs);
CCoinsViewCache &viewChain = *pcoinsTip;
- CCoinsViewMemPool viewMempool(viewChain, mempool);
+ CCoinsViewMemPool viewMempool(&viewChain, mempool);
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
@@ -612,21 +615,19 @@ Value signrawtransaction(const Array& params, bool fHelp)
vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
- CCoins coins;
- if (view.GetCoins(txid, coins)) {
- if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
+ {
+ CCoinsModifier coins = view.ModifyCoins(txid);
+ if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
string err("Previous output scriptPubKey mismatch:\n");
- err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
+ err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
scriptPubKey.ToString();
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
}
- // what todo if txid is known, but the actual output isn't?
+ if ((unsigned int)nOut >= coins->vout.size())
+ coins->vout.resize(nOut+1);
+ coins->vout[nOut].scriptPubKey = scriptPubKey;
+ coins->vout[nOut].nValue = 0; // we don't know the actual output value
}
- if ((unsigned int)nOut >= coins.vout.size())
- coins.vout.resize(nOut+1);
- coins.vout[nOut].scriptPubKey = scriptPubKey;
- coins.vout[nOut].nValue = 0; // we don't know the actual output value
- view.SetCoins(txid, coins);
// if redeemScript given and not using the local wallet (private keys
// given), add redeemScript to the tempKeystore so it can be signed:
@@ -687,7 +688,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
- if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STANDARD_SCRIPT_VERIFY_FLAGS))
+ if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(mergedTx, i)))
fComplete = false;
}
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 632c46acd5..d7c0c0ef5c 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -230,15 +230,20 @@ Value setaccount(const Array& params, bool fHelp)
if (params.size() > 1)
strAccount = AccountFromValue(params[1]);
- // Detect when changing the account of an address that is the 'unused current key' of another account:
- if (pwalletMain->mapAddressBook.count(address.Get()))
+ // Only add the account if the address is yours.
+ if (IsMine(*pwalletMain, address.Get()))
{
- string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
- if (address == GetAccountAddress(strOldAccount))
- GetAccountAddress(strOldAccount, true);
+ // Detect when changing the account of an address that is the 'unused current key' of another account:
+ if (pwalletMain->mapAddressBook.count(address.Get()))
+ {
+ string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
+ if (address == GetAccountAddress(strOldAccount))
+ GetAccountAddress(strOldAccount, true);
+ }
+ pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
}
-
- pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
+ else
+ throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
return Value::null;
}
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index a71f55dd26..ae66217b7c 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -9,14 +9,10 @@
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
#include "crypto/sha2.h"
-#include "random.h"
#include "script/script.h"
#include "uint256.h"
#include "util.h"
-#include <boost/thread.hpp>
-#include <boost/tuple/tuple_comparison.hpp>
-
using namespace std;
typedef vector<unsigned char> valtype;
@@ -56,10 +52,7 @@ static inline void popstack(vector<valtype>& stack)
stack.pop_back();
}
-bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) {
- if (!(flags & SCRIPT_VERIFY_STRICTENC))
- return true;
-
+bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
if (vchPubKey.size() < 33)
return error("Non-canonical public key: too short");
if (vchPubKey[0] == 0x04) {
@@ -74,10 +67,7 @@ bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) {
return true;
}
-bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) {
- if (!(flags & SCRIPT_VERIFY_STRICTENC))
- return true;
-
+bool static IsDERSignature(const valtype &vchSig) {
// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
// A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
// Where R and S are not negative (their first byte has its highest bit not set), and not
@@ -87,9 +77,6 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) {
return error("Non-canonical signature: too short");
if (vchSig.size() > 73)
return error("Non-canonical signature: too long");
- unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY));
- if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
- return error("Non-canonical signature: unknown hashtype byte");
if (vchSig[0] != 0x30)
return error("Non-canonical signature: wrong type");
if (vchSig[1] != vchSig.size()-3)
@@ -121,18 +108,55 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) {
if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80))
return error("Non-canonical signature: S value excessively padded");
- if (flags & SCRIPT_VERIFY_LOW_S) {
- // If the S value is above the order of the curve divided by two, its
- // complement modulo the order could have been used instead, which is
- // one byte shorter when encoded correctly.
- if (!CKey::CheckSignatureElement(S, nLenS, true))
- return error("Non-canonical signature: S value is unnecessarily high");
+ return true;
+}
+
+bool static IsLowDERSignature(const valtype &vchSig) {
+ if (!IsDERSignature(vchSig)) {
+ return false;
}
+ unsigned int nLenR = vchSig[3];
+ unsigned int nLenS = vchSig[5+nLenR];
+ const unsigned char *S = &vchSig[6+nLenR];
+ // If the S value is above the order of the curve divided by two, its
+ // complement modulo the order could have been used instead, which is
+ // one byte shorter when encoded correctly.
+ if (!CKey::CheckSignatureElement(S, nLenS, true))
+ return error("Non-canonical signature: S value is unnecessarily high");
return true;
}
-bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags)
+bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
+ if (vchSig.size() == 0) {
+ return false;
+ }
+ unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY));
+ if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
+ return error("Non-canonical signature: unknown hashtype byte");
+
+ return true;
+}
+
+bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags) {
+ if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsDERSignature(vchSig)) {
+ return false;
+ } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig)) {
+ return false;
+ } else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) {
+ return false;
+ }
+ return true;
+}
+
+bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags) {
+ if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchSig)) {
+ return false;
+ }
+ return true;
+}
+
+bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker)
{
CScript::const_iterator pc = script.begin();
CScript::const_iterator pend = script.end();
@@ -674,8 +698,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
// Drop the signature, since there's no way for a signature to sign itself
scriptCode.FindAndDelete(CScript(vchSig));
- bool fSuccess = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) &&
- CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, flags);
+ if (!CheckSignatureEncoding(vchSig, flags)) {
+ return false;
+ }
+
+ bool fSuccess = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode);
popstack(stack);
popstack(stack);
@@ -734,9 +761,12 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
valtype& vchSig = stacktop(-isig);
valtype& vchPubKey = stacktop(-ikey);
+ if (!CheckSignatureEncoding(vchSig, flags)) {
+ return false;
+ }
+
// Check signature
- bool fOk = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) &&
- CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, flags);
+ bool fOk = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode);
if (fOk) {
isig++;
@@ -897,7 +927,7 @@ public:
} // anon namespace
-uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
+uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
{
if (nIn >= txTo.vin.size()) {
LogPrintf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn);
@@ -921,70 +951,19 @@ uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsig
return ss.GetHash();
}
-// Valid signature cache, to avoid doing expensive ECDSA signature checking
-// twice for every transaction (once when accepted into memory pool, and
-// again when accepted into the block chain)
-class CSignatureCache
+bool SignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
{
-private:
- // sigdata_type is (signature hash, signature, public key):
- typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type;
- std::set< sigdata_type> setValid;
- boost::shared_mutex cs_sigcache;
-
-public:
- bool
- Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
- {
- boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
-
- sigdata_type k(hash, vchSig, pubKey);
- std::set<sigdata_type>::iterator mi = setValid.find(k);
- if (mi != setValid.end())
- return true;
- return false;
- }
-
- void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
- {
- // DoS prevention: limit cache size to less than 10MB
- // (~200 bytes per cache entry times 50,000 entries)
- // Since there are a maximum of 20,000 signature operations per block
- // 50,000 is a reasonable default.
- int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
- if (nMaxCacheSize <= 0) return;
-
- boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
-
- while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize)
- {
- // Evict a random entry. Random because that helps
- // foil would-be DoS attackers who might try to pre-generate
- // and re-use a set of valid signatures just-slightly-greater
- // than our cache size.
- uint256 randomHash = GetRandHash();
- std::vector<unsigned char> unused;
- std::set<sigdata_type>::iterator it =
- setValid.lower_bound(sigdata_type(randomHash, unused, unused));
- if (it == setValid.end())
- it = setValid.begin();
- setValid.erase(*it);
- }
-
- sigdata_type k(hash, vchSig, pubKey);
- setValid.insert(k);
- }
-};
+ return pubkey.Verify(sighash, vchSig);
+}
-bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int flags)
+bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
{
- static CSignatureCache signatureCache;
-
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
return false;
// Hash type is one byte tacked on to the end of the signature
+ vector<unsigned char> vchSig(vchSigIn);
if (vchSig.empty())
return false;
int nHashType = vchSig.back();
@@ -992,26 +971,20 @@ bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char>& vchPubK
uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType);
- if (signatureCache.Get(sighash, vchSig, pubkey))
- return true;
-
- if (!pubkey.Verify(sighash, vchSig))
+ if (!VerifySignature(vchSig, pubkey, sighash))
return false;
- if (!(flags & SCRIPT_VERIFY_NOCACHE))
- signatureCache.Set(sighash, vchSig, pubkey);
-
return true;
}
-bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags)
+bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker)
{
vector<vector<unsigned char> > stack, stackCopy;
- if (!EvalScript(stack, scriptSig, txTo, nIn, flags))
+ if (!EvalScript(stack, scriptSig, flags, checker))
return false;
if (flags & SCRIPT_VERIFY_P2SH)
stackCopy = stack;
- if (!EvalScript(stack, scriptPubKey, txTo, nIn, flags))
+ if (!EvalScript(stack, scriptPubKey, flags, checker))
return false;
if (stack.empty())
return false;
@@ -1034,7 +1007,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
popstack(stackCopy);
- if (!EvalScript(stackCopy, pubKey2, txTo, nIn, flags))
+ if (!EvalScript(stackCopy, pubKey2, flags, checker))
return false;
if (stackCopy.empty())
return false;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index adca2142ac..de5ce2ced1 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -10,6 +10,7 @@
#include <stdint.h>
#include <string>
+class CPubKey;
class CScript;
class CTransaction;
class uint256;
@@ -27,19 +28,54 @@ enum
enum
{
SCRIPT_VERIFY_NONE = 0,
- SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
- SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys
- SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC)
- SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it)
- SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length
-};
-bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags);
-bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int flags);
+ // Evaluate P2SH subscripts (softfork safe, BIP16).
+ SCRIPT_VERIFY_P2SH = (1U << 0),
+
+ // Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
+ // Passing a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) to checksig causes that pubkey to be
+ // skipped (not softfork safe: this flag can widen the validity of OP_CHECKSIG OP_NOT).
+ SCRIPT_VERIFY_STRICTENC = (1U << 1),
+
+ // Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1)
+ SCRIPT_VERIFY_DERSIG = (1U << 2),
+
+ // Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
+ // (softfork safe, BIP62 rule 5).
+ SCRIPT_VERIFY_LOW_S = (1U << 3),
+
+ // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7).
+ SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
+};
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
-bool CheckSig(std::vector<unsigned char> vchSig, const std::vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int flags);
-bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags);
-bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags);
+
+class BaseSignatureChecker
+{
+public:
+ virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
+ {
+ return false;
+ }
+
+ virtual ~BaseSignatureChecker() {}
+};
+
+class SignatureChecker : public BaseSignatureChecker
+{
+private:
+ const CTransaction& txTo;
+ unsigned int nIn;
+
+protected:
+ virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
+
+public:
+ SignatureChecker(const CTransaction& txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
+ bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
+};
+
+bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker);
+bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker);
#endif // H_BITCOIN_SCRIPT_INTERPRETER
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
new file mode 100644
index 0000000000..ab366898d8
--- /dev/null
+++ b/src/script/sigcache.cpp
@@ -0,0 +1,88 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "sigcache.h"
+
+#include "key.h"
+#include "random.h"
+#include "uint256.h"
+#include "util.h"
+
+#include <boost/thread.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+
+namespace {
+
+// Valid signature cache, to avoid doing expensive ECDSA signature checking
+// twice for every transaction (once when accepted into memory pool, and
+// again when accepted into the block chain)
+class CSignatureCache
+{
+private:
+ // sigdata_type is (signature hash, signature, public key):
+ typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type;
+ std::set< sigdata_type> setValid;
+ boost::shared_mutex cs_sigcache;
+
+public:
+ bool
+ Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
+ {
+ boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
+
+ sigdata_type k(hash, vchSig, pubKey);
+ std::set<sigdata_type>::iterator mi = setValid.find(k);
+ if (mi != setValid.end())
+ return true;
+ return false;
+ }
+
+ void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
+ {
+ // DoS prevention: limit cache size to less than 10MB
+ // (~200 bytes per cache entry times 50,000 entries)
+ // Since there are a maximum of 20,000 signature operations per block
+ // 50,000 is a reasonable default.
+ int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
+ if (nMaxCacheSize <= 0) return;
+
+ boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
+
+ while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize)
+ {
+ // Evict a random entry. Random because that helps
+ // foil would-be DoS attackers who might try to pre-generate
+ // and re-use a set of valid signatures just-slightly-greater
+ // than our cache size.
+ uint256 randomHash = GetRandHash();
+ std::vector<unsigned char> unused;
+ std::set<sigdata_type>::iterator it =
+ setValid.lower_bound(sigdata_type(randomHash, unused, unused));
+ if (it == setValid.end())
+ it = setValid.begin();
+ setValid.erase(*it);
+ }
+
+ sigdata_type k(hash, vchSig, pubKey);
+ setValid.insert(k);
+ }
+};
+
+}
+
+bool CachingSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
+{
+ static CSignatureCache signatureCache;
+
+ if (signatureCache.Get(sighash, vchSig, pubkey))
+ return true;
+
+ if (!SignatureChecker::VerifySignature(vchSig, pubkey, sighash))
+ return false;
+
+ if (store)
+ signatureCache.Set(sighash, vchSig, pubkey);
+ return true;
+}
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
new file mode 100644
index 0000000000..46b8f4d335
--- /dev/null
+++ b/src/script/sigcache.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef H_BITCOIN_SCRIPT_SIGCACHE
+#define H_BITCOIN_SCRIPT_SIGCACHE
+
+#include "script/interpreter.h"
+
+#include <vector>
+
+class CPubKey;
+
+class CachingSignatureChecker : public SignatureChecker
+{
+private:
+ bool store;
+
+public:
+ CachingSignatureChecker(const CTransaction& txToIn, unsigned int nInIn, bool storeIn=true) : SignatureChecker(txToIn, nInIn), store(storeIn) {}
+
+ bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
+};
+
+#endif // H_BITCOIN_SCRIPT_SIGCACHE
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 8abd8d221d..da77e7d1f1 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -123,7 +123,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutabl
}
// Test solution
- return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS);
+ return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(txTo, nIn));
}
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
@@ -174,7 +174,7 @@ static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction&
if (sigs.count(pubkey))
continue; // Already got a sig for this pubkey
- if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0))
+ if (SignatureChecker(txTo, nIn).CheckSig(sig, pubkey, scriptPubKey))
{
sigs[pubkey] = sig;
break;
@@ -252,9 +252,9 @@ CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsign
Solver(scriptPubKey, txType, vSolutions);
vector<valtype> stack1;
- EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC);
+ EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
vector<valtype> stack2;
- EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC);
+ EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
}
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 407baf621d..53ae254d59 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -203,7 +203,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
if (whichType == TX_PUBKEY)
{
- addressRet = CPubKey(vSolutions[0]).GetID();
+ CPubKey pubKey(vSolutions[0]);
+ if (!pubKey.IsValid())
+ return false;
+
+ addressRet = pubKey.GetID();
return true;
}
else if (whichType == TX_PUBKEYHASH)
@@ -237,9 +241,16 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto
nRequiredRet = vSolutions.front()[0];
for (unsigned int i = 1; i < vSolutions.size()-1; i++)
{
- CTxDestination address = CPubKey(vSolutions[i]).GetID();
+ CPubKey pubKey(vSolutions[i]);
+ if (!pubKey.IsValid())
+ continue;
+
+ CTxDestination address = pubKey.GetID();
addressRet.push_back(address);
}
+
+ if (addressRet.empty())
+ return false;
}
else
{
diff --git a/src/serialize.h b/src/serialize.h
index 68501facf2..ff11edc06c 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -1154,7 +1154,7 @@ public:
-/** 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().
@@ -1166,12 +1166,13 @@ private:
// Disallow copies
CAutoFile(const CAutoFile&);
CAutoFile& operator=(const CAutoFile&);
-protected:
- FILE* file;
-public:
+
int nType;
int nVersion;
+
+ FILE* file;
+public:
CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn)
{
file = filenew;
@@ -1186,9 +1187,10 @@ public:
void fclose()
{
- if (file != NULL && file != stdin && file != stdout && file != stderr)
+ if (file) {
::fclose(file);
- file = NULL;
+ file = NULL;
+ }
}
FILE* release() { FILE* ret = file; file = NULL; return ret; }
@@ -1256,13 +1258,23 @@ public:
}
};
-/** 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).
+ */
class CBufferedFile
{
private:
- FILE *src; // source file
+ // 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
@@ -1289,12 +1301,25 @@ protected:
}
public:
- int nType;
- int nVersion;
-
CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
- src(fileIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0),
- 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();
+ }
+
+ void fclose()
+ {
+ if (src) {
+ ::fclose(src);
+ src = NULL;
+ }
}
// check whether we're at the end of the source file
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index 58fffb6df4..c298c805da 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest);
}
}
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(CBaseChainParams::UNITTEST);
}
// Goal: check that generated keys match test vectors
@@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
CTxDestination nodest = CNoDestination();
BOOST_CHECK(!dummyAddr.Set(nodest));
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(CBaseChainParams::UNITTEST);
}
// Goal: check that base58 parsing code is robust against a variety of corrupted data
diff --git a/src/test/canonical_tests.cpp b/src/test/canonical_tests.cpp
deleted file mode 100644
index a17099de72..0000000000
--- a/src/test/canonical_tests.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2012-2013 The Bitcoin Core developers
-// Distributed under the MIT/X11 software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-//
-// Unit tests for canonical signatures
-//
-
-#include "data/sig_noncanonical.json.h"
-#include "data/sig_canonical.json.h"
-#include "key.h"
-#include "random.h"
-#include "script/interpreter.h"
-#include "util.h"
-#include "utilstrencodings.h"
-
-#include <boost/foreach.hpp>
-#include <boost/test/unit_test.hpp>
-#include "json/json_spirit_writer_template.h"
-#include <openssl/ecdsa.h>
-
-using namespace std;
-using namespace json_spirit;
-
-// In script_tests.cpp
-extern Array read_json(const std::string& jsondata);
-
-BOOST_AUTO_TEST_SUITE(canonical_tests)
-
-// OpenSSL-based test for canonical signature (without test for hashtype byte)
-bool static IsCanonicalSignature_OpenSSL_inner(const std::vector<unsigned char>& vchSig)
-{
- if (vchSig.size() == 0)
- return false;
- const unsigned char *input = &vchSig[0];
- ECDSA_SIG *psig = NULL;
- d2i_ECDSA_SIG(&psig, &input, vchSig.size());
- if (psig == NULL)
- return false;
- unsigned char buf[256];
- unsigned char *pbuf = buf;
- unsigned int nLen = i2d_ECDSA_SIG(psig, NULL);
- if (nLen != vchSig.size()) {
- ECDSA_SIG_free(psig);
- return false;
- }
- nLen = i2d_ECDSA_SIG(psig, &pbuf);
- ECDSA_SIG_free(psig);
- return (memcmp(&vchSig[0], &buf[0], nLen) == 0);
-}
-
-// OpenSSL-based test for canonical signature
-bool static IsCanonicalSignature_OpenSSL(const std::vector<unsigned char> &vchSignature) {
- if (vchSignature.size() < 1)
- return false;
- if (vchSignature.size() > 127)
- return false;
- if (vchSignature[vchSignature.size() - 1] & 0x7C)
- return false;
-
- std::vector<unsigned char> vchSig(vchSignature);
- vchSig.pop_back();
- if (!IsCanonicalSignature_OpenSSL_inner(vchSig))
- return false;
- return true;
-}
-
-BOOST_AUTO_TEST_CASE(script_canon)
-{
- Array tests = read_json(std::string(json_tests::sig_canonical, json_tests::sig_canonical + sizeof(json_tests::sig_canonical)));
-
- BOOST_FOREACH(Value &tv, tests) {
- string test = tv.get_str();
- if (IsHex(test)) {
- std::vector<unsigned char> sig = ParseHex(test);
- BOOST_CHECK_MESSAGE(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test);
- BOOST_CHECK_MESSAGE(IsCanonicalSignature_OpenSSL(sig), test);
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE(script_noncanon)
-{
- Array tests = read_json(std::string(json_tests::sig_noncanonical, json_tests::sig_noncanonical + sizeof(json_tests::sig_noncanonical)));
-
- BOOST_FOREACH(Value &tv, tests) {
- string test = tv.get_str();
- if (IsHex(test)) {
- std::vector<unsigned char> sig = ParseHex(test);
- BOOST_CHECK_MESSAGE(!IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test);
- BOOST_CHECK_MESSAGE(!IsCanonicalSignature_OpenSSL(sig), test);
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE(script_signstrict)
-{
- for (int i=0; i<100; i++) {
- CKey key;
- key.MakeNewKey(i & 1);
- std::vector<unsigned char> sig;
- uint256 hash = GetRandHash();
-
- BOOST_CHECK(key.Sign(hash, sig)); // Generate a random signature.
- BOOST_CHECK(key.GetPubKey().Verify(hash, sig)); // Check it.
- sig.push_back(0x01); // Append a sighash type.
-
- BOOST_CHECK(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_LOW_S));
- BOOST_CHECK(IsCanonicalSignature_OpenSSL(sig));
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
new file mode 100644
index 0000000000..3ecd301bc7
--- /dev/null
+++ b/src/test/coins_tests.cpp
@@ -0,0 +1,178 @@
+// Copyright (c) 2014 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 "coins.h"
+#include "random.h"
+#include "uint256.h"
+
+#include <vector>
+#include <map>
+
+#include <boost/test/unit_test.hpp>
+
+namespace
+{
+class CCoinsViewTest : public CCoinsView
+{
+ uint256 hashBestBlock_;
+ std::map<uint256, CCoins> map_;
+
+public:
+ bool GetCoins(const uint256& txid, CCoins& coins) const
+ {
+ std::map<uint256, CCoins>::const_iterator it = map_.find(txid);
+ if (it == map_.end()) {
+ return false;
+ }
+ coins = it->second;
+ if (coins.IsPruned() && insecure_rand() % 2 == 0) {
+ // Randomly return false in case of an empty entry.
+ return false;
+ }
+ return true;
+ }
+
+ bool HaveCoins(const uint256& txid) const
+ {
+ CCoins coins;
+ return GetCoins(txid, coins);
+ }
+
+ uint256 GetBestBlock() const { return hashBestBlock_; }
+
+ bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock)
+ {
+ for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) {
+ map_[it->first] = it->second.coins;
+ if (it->second.coins.IsPruned() && insecure_rand() % 3 == 0) {
+ // Randomly delete empty entries on write.
+ map_.erase(it->first);
+ }
+ mapCoins.erase(it++);
+ }
+ mapCoins.clear();
+ hashBestBlock_ = hashBlock;
+ return true;
+ }
+
+ bool GetStats(CCoinsStats& stats) const { return false; }
+};
+}
+
+BOOST_AUTO_TEST_SUITE(coins_tests)
+
+static const unsigned int NUM_SIMULATION_ITERATIONS = 40000;
+
+// 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 CCoins 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 removed_an_entry = false;
+ bool updated_an_entry = false;
+ bool found_an_entry = false;
+ bool missed_an_entry = false;
+
+ // A simple map to track what we expect the cache stack to represent.
+ std::map<uint256, CCoins> result;
+
+ // The cache stack.
+ CCoinsViewTest base; // A CCoinsViewTest at the bottom.
+ std::vector<CCoinsViewCache*> stack; // A stack of CCoinsViewCaches on top.
+ stack.push_back(new CCoinsViewCache(&base)); // Start with one cache.
+
+ // Use a limited set of random transaction ids, so we do test overwriting entries.
+ std::vector<uint256> 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.
+ CCoins& coins = result[txid];
+ CCoinsModifier entry = stack.back()->ModifyCoins(txid);
+ BOOST_CHECK(coins == *entry);
+ if (insecure_rand() % 5 == 0 || coins.IsPruned()) {
+ if (coins.IsPruned()) {
+ added_an_entry = true;
+ } else {
+ updated_an_entry = true;
+ }
+ coins.nVersion = insecure_rand();
+ coins.vout.resize(1);
+ coins.vout[0].nValue = insecure_rand();
+ *entry = coins;
+ } else {
+ coins.Clear();
+ entry->Clear();
+ removed_an_entry = true;
+ }
+ }
+
+ // Once every 1000 iterations and at the end, verify the full cache.
+ if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
+ for (std::map<uint256, CCoins>::iterator it = result.begin(); it != result.end(); it++) {
+ const CCoins* coins = stack.back()->AccessCoins(it->first);
+ if (coins) {
+ BOOST_CHECK(*coins == it->second);
+ found_an_entry = true;
+ } else {
+ BOOST_CHECK(it->second.IsPruned());
+ missed_an_entry = true;
+ }
+ }
+ }
+
+ if (insecure_rand() % 100 == 0) {
+ // Every 100 iterations, change the cache stack.
+ if (stack.size() > 0 && insecure_rand() % 2 == 0) {
+ stack.back()->Flush();
+ delete stack.back();
+ stack.pop_back();
+ }
+ if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) {
+ CCoinsView* tip = &base;
+ if (stack.size() > 0) {
+ tip = stack.back();
+ } else {
+ removed_all_caches = true;
+ }
+ stack.push_back(new CCoinsViewCache(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(removed_an_entry);
+ BOOST_CHECK(updated_an_entry);
+ BOOST_CHECK(found_an_entry);
+ BOOST_CHECK(missed_an_entry);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index 35a6794b01..b6447cb221 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -384,19 +384,126 @@ nSequences are max.
["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
-["0x47 0x30440220304eff7556bba9560df47873275e64db45f3cd735998ce3f00d2e57b1bb5f31302205c0c9d14b8b80d43e2ac9b87532f1af6d8a3271262bc694ec4e14068392bb0a001", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", "P2PK, bad sig"],
-["0x47 0x3044022037fcdb8e08f41e27588de8bc036d2c4b16eb3d09c1ba53b8f47a0a9c27722a39022058664b7a53b507e71dfafb77193e3786c3f0c119d78ce9104480ee7ece04f09301 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG", "", "P2PKH, bad pubkey"],
-["0x47 0x3044022035e5b6742d299861c84cebaf2ea64145ee427a95facab39e2594d6deebb0c1d602200acb16778faa2e467a59006f342f2535b1418d55ba63a8605b387b7f9ac86d9a01", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", "P2PK anyonecanpay marked with normal hashtype"],
-["0x47 0x3044022029b2b8765ca950cf75a69e80b73b7ddfcaa8b27080c2db4c23b36aae60688e790220598ff368e17872ee065aa54d7d3a590682ca5204325b23b31d7da3c4a21ae67901 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", "P2SH", "P2SH(P2PK), bad redeemscript"],
-["0x47 0x30440220647f906e63890df5ef1d3fed47ba892b31976c634281079e2bd38504fb54a1fb022021e8811f38fbe90efb6b74cb78da01d9badbac3bafdf70a861d7538a220d0b2601 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", "P2SH", "P2SH(P2PKH), bad sig"],
-["0 0x47 0x304402203ef170402f8887f2ac183f31b1f503b0bc60bfc968dd469b097ea6124aefac5002200612febadc4e4cacc086982cb85830a17af3680c1b6a3cf77c1708af7621cf1301 0 0x47 0x304402207821838251a24a2234844f68e7169e6d11945cdf052ea12bd3e4e37457aceb4402200b6b46c81361e314c740ae5133c072af5fa5c209d65d2db1679e1716f19a538101", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3, 2 sigs"],
-["0 0 0x47 0x304402204661f7795e8db7be3132e8974e9a76d1d24b31f23df94c6fbcea07d1c205789102203f5e45a1c0b085279b58d11b36d5fea5449c3cf16f844ad10124e9b65e8777d201 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", "P2SH", "P2SH(2-of-3), 1 sig"],
-["0x47 0x304402200052bc1600ca45c71f3538720fe62a5e8548dffd137af04467598c98466e9c0a0220789318ddbc9991ee477974089220a2feb6a6298a7c93d5ff6c25a92a2f4b48d501", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "STRICTENC", "P2PK with too much R padding"],
-["0x48 0x304502206eb7b92628bfb3c4d2a04b65b986987bcbb1af4fceedb144d5a0437b7ee410590221005f57a52df4aa26366742eed0db182fce51fbcd7159011b0644a7c05943eb228901", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "STRICTENC", "P2PK with too much S padding"],
-["0x47 0x30440220d8ad1efd55a3d2b8896495c38aba72056e1b3ca4a6ca15760e843eb1a9b9907602203eb0e8f3d6bec998262dfd03eaeb0f31c4e5105965436dec77550724b3771f3201", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "STRICTENC", "P2PK with too little R padding"],
-["0x48 0x304502206c43e065c8a8db3bbe69015afb86a51fb2fc8870defd41d436da2a197d9d6c12022100fcec35816ee2d84ec271ad159fcabf5dd712157051169e48ac328a7818cdb51e01", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "LOW_S,STRICTENC", "P2PK with high S"],
-["0x01 0x01 0x47 0x304402200e48ba1cf4d7182db94ffb57bd72ea31b5545dc0d1c512e665779b4fb2badc52022054b8388dfc074c708a75b62359b7be46402751ee40c0a111aef38a837b6ed09801 0x47 0x304402201c9820f59c49107bb30e6175cfc9ec95f897b03beb628b4bc854d2b80392aa0602200235d986ae418bcd111b8814f4c26a0ab5f475fb542a44884fc14912a97a252301 0x47 0x304402204cd7894c6f10a871f5b0c1f9c13228f8cdd4050248f0d0f498ee86be69ee3080022051bd2932c7d585eb600c7194235c74da820935f0d67972fd9545673aa1fd023301", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "NULLDUMMY", "3-of-3 with nonzero dummy"],
+[
+ "0x47 0x30440220304eff7556bba9560df47873275e64db45f3cd735998ce3f00d2e57b1bb5f31302205c0c9d14b8b80d43e2ac9b87532f1af6d8a3271262bc694ec4e14068392bb0a001",
+ "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
+ "",
+ "P2PK, bad sig"
+],
+[
+ "0x47 0x3044022037fcdb8e08f41e27588de8bc036d2c4b16eb3d09c1ba53b8f47a0a9c27722a39022058664b7a53b507e71dfafb77193e3786c3f0c119d78ce9104480ee7ece04f09301 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640",
+ "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG",
+ "",
+ "P2PKH, bad pubkey"
+],
+[
+ "0x47 0x3044022035e5b6742d299861c84cebaf2ea64145ee427a95facab39e2594d6deebb0c1d602200acb16778faa2e467a59006f342f2535b1418d55ba63a8605b387b7f9ac86d9a01",
+ "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
+ "",
+ "P2PK anyonecanpay marked with normal hashtype"
+],
+[
+ "0x47 0x3044022029b2b8765ca950cf75a69e80b73b7ddfcaa8b27080c2db4c23b36aae60688e790220598ff368e17872ee065aa54d7d3a590682ca5204325b23b31d7da3c4a21ae67901 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
+ "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL",
+ "P2SH",
+ "P2SH(P2PK), bad redeemscript"
+],
+[
+ "0x47 0x30440220647f906e63890df5ef1d3fed47ba892b31976c634281079e2bd38504fb54a1fb022021e8811f38fbe90efb6b74cb78da01d9badbac3bafdf70a861d7538a220d0b2601 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
+ "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",
+ "P2SH",
+ "P2SH(P2PKH), bad sig"
+],
+[
+ "0 0x47 0x304402203ef170402f8887f2ac183f31b1f503b0bc60bfc968dd469b097ea6124aefac5002200612febadc4e4cacc086982cb85830a17af3680c1b6a3cf77c1708af7621cf1301 0 0x47 0x304402207821838251a24a2234844f68e7169e6d11945cdf052ea12bd3e4e37457aceb4402200b6b46c81361e314c740ae5133c072af5fa5c209d65d2db1679e1716f19a538101",
+ "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
+ "",
+ "3-of-3, 2 sigs"
+],
+[
+ "0 0 0x47 0x304402204661f7795e8db7be3132e8974e9a76d1d24b31f23df94c6fbcea07d1c205789102203f5e45a1c0b085279b58d11b36d5fea5449c3cf16f844ad10124e9b65e8777d201 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",
+ "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL",
+ "P2SH",
+ "P2SH(2-of-3), 1 sig"
+],
+[
+ "0x47 0x304402200052bc1600ca45c71f3538720fe62a5e8548dffd137af04467598c98466e9c0a0220789318ddbc9991ee477974089220a2feb6a6298a7c93d5ff6c25a92a2f4b48d501",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "STRICTENC",
+ "P2PK with too much R padding"
+],
+[
+ "0x48 0x304502206eb7b92628bfb3c4d2a04b65b986987bcbb1af4fceedb144d5a0437b7ee410590221005f57a52df4aa26366742eed0db182fce51fbcd7159011b0644a7c05943eb228901",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "STRICTENC",
+ "P2PK with too much S padding"
+],
+[
+ "0x47 0x30440220d8ad1efd55a3d2b8896495c38aba72056e1b3ca4a6ca15760e843eb1a9b9907602203eb0e8f3d6bec998262dfd03eaeb0f31c4e5105965436dec77550724b3771f3201",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "STRICTENC",
+ "P2PK with too little R padding"
+],
+[
+ "0x47 0x30440220001d0f82c127470cb38316c96b1719b33382353687a1146a776dee8259606905022062cd1fc8eacef819d68f0f41cc9ae9fdc2e29b70c3c7ad2c6c18f39b4e35c42701",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
+ "DERSIG",
+ "P2PK NOT with bad sig with too much R padding"
+],
+[
+ "0x47 0x30440220005d727e2a82d6e8a98a6da6fbc281325644d1a40455e386fdb17883a8e6bc4d02202d15cca42ce136047a980d288e60c679d7e84cce18c3ceffb6bc81b9e9ba517801",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
+ "",
+ "P2PK NOT with too much R padding but no DERSIG"
+],
+[
+ "0x47 0x30440220006e8bc4f82032b12bd594847c16d8b2986de734aa3b0528bd89d664d41e6d1c02200cfd582694891bcfa2e630e899bda257486eba00a007222fae71144dba07dc2901",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
+ "DERSIG",
+ "P2PK NOT with too much R padding"
+],
+[
+ "0x48 0x304502206c43e065c8a8db3bbe69015afb86a51fb2fc8870defd41d436da2a197d9d6c12022100fcec35816ee2d84ec271ad159fcabf5dd712157051169e48ac328a7818cdb51e01",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
+ "LOW_S,STRICTENC",
+ "P2PK with high S"
+],
+[
+ "0x47 0x304402203aab50cd7c30cc1e1475dee615b295bcee6ccf8aa8a7f6cda6b696c70d79cbb40220558e43fe7596c31146e2d077698d5a9c38351d8ba567549a2ae43ca97231c39501",
+ "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
+ "STRICTENC",
+ "P2PK with hybrid pubkey"
+],
+[
+ "0x47 0x304402205745e8f846110c185ee1185c01843a108588b81463d2c34d4a3f2445529f12fe02206ee6a2657bbc4e2bb74bfc44c3a5c4f410ed6356ca68982465de6ca807c807c201",
+ "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
+ "",
+ "P2PK NOT with hybrid pubkey but no STRICTENC"
+],
+[
+ "0x47 0x304402201f82b99a813c9c48c8dee8d2c43b8f637b72353fe9bdcc084537bc17e2ab770402200c43b96a5f7e115f0114eabda32e068145965cb6c7b5ef64833bb4fcf9fc1b3b05",
+ "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
+ "STRICTENC",
+ "P2PK with undefined hashtype"
+],
+[
+ "0x47 0x30440220166848cd5b82a32b5944d90de3c35249354b43773c2ece1844ee8d1103e2f6c602203b6b046da4243c77adef80ada9201b27bbfdf7f9d5428f40434b060432afd62005",
+ "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT",
+ "STRICTENC",
+ "P2PK NOT with invalid sig and undefined hashtype"
+],
+[
+ "0x01 0x01 0x47 0x304402200e48ba1cf4d7182db94ffb57bd72ea31b5545dc0d1c512e665779b4fb2badc52022054b8388dfc074c708a75b62359b7be46402751ee40c0a111aef38a837b6ed09801 0x47 0x304402201c9820f59c49107bb30e6175cfc9ec95f897b03beb628b4bc854d2b80392aa0602200235d986ae418bcd111b8814f4c26a0ab5f475fb542a44884fc14912a97a252301 0x47 0x304402204cd7894c6f10a871f5b0c1f9c13228f8cdd4050248f0d0f498ee86be69ee3080022051bd2932c7d585eb600c7194235c74da820935f0d67972fd9545673aa1fd023301",
+ "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
+ "NULLDUMMY",
+ "3-of-3 with nonzero dummy"
+],
+[
+ "0x01 0x01 0x47 0x304402201847fc3b8f7597768e7f543c58da1fca6e8e35eb28979431e6b637572ce6eaa4022048dd58608e040841d0bf52a70cfb70e1a9c8d2826fad068f4e9d2bf5c87766a501 0x47 0x30440220711311a72516affed73363763983d05c3d6a06a2eadf5d76b90b4354162ba94302204841a69e5955a7dc8e4ab3105fd0c86040c1dac6016297a51ddbf5079c28756801 0x47 0x30440220267e331a378191e7282fd10d61c97bf74bc97c233c5833d677936424ac08dee502201eee83d88b91988e1c4d9b979df2404aa190e0987a8ca09c4e5cd61da1d48ecc01",
+ "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT",
+ "NULLDUMMY",
+ "3-of-3 NOT with invalid sig with nonzero dummy"
+],
["The End"]
-
]
diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
index 653f60d982..88bec7238c 100644
--- a/src/test/data/script_valid.json
+++ b/src/test/data/script_valid.json
@@ -529,19 +529,126 @@ nSequences are max.
["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
-["0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", "P2PK"],
-["0x47 0x3044022069d40999786aeb2fd874f9eb2636461a062dc963471627ed8390a3a5f9556f640220350132a52415ce622f2aadd07f791c591500917ec1f8c5edbc5381ef7942534d01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", "DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG", "", "P2PKH"],
-["0x47 0x30440220519f2a6632ffa134c7811ea2819e9dcc951f0c7baf461f2dffdd09133f3b080a02203ec6bab5eb6619ed7f41b8701d7c6d70cfc83bb26c5c97f54b2ca6e304fc2bb581", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", "P2PK anyonecanpay"],
-["0x47 0x30440220279dad2170ffb5639f0a1ea71fc462ee37d75d420d86f84c978bac523c09b7f20220683b2789f5c5528a9e0a0d78f6e40db3f616cf1adb5a5fdef117d5974795cfe201 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", "P2SH", "P2SH(P2PK)"],
-["0x47 0x3044022066acbfb5ac96b7cbf3f05a2aaf358c32438c45d1d7359dee9fc1ee636940735f02205606a03fd8cbf6a6fcbcba60c8abb1e385c0b5753cb57a97538159106fd3684e01 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", "", "P2SH(P2PKH), bad sig but no VERIFY_P2SH"],
-["0 0x47 0x3044022004e791dd30a64c70e55e84e150c002af9feb3ce0ab1f20e86c53d1209003927502205a60453987fcd72aebaaacebc8ce4b15449cdd79e54cc82cefb83e69dbcfeabf01 0x47 0x304402201d021808ce93dd8574cc4f99ae4f11b44305528b0aecbd9f156f08315173643802200944a0ea5c884bd86180aef76d8b1e444860776b251e47d2d6c651a1c6f9930801 0x47 0x30440220446336d7b7de05ebb5683b82b05248ec7d78e88ae8d6125985f5776c887a4cf90220674ab2b2c2f954ba1cf35457d273c90d0c0c1c224d0ae128628740e81129486801", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3"],
-["0 0x47 0x30440220288b06d057cf0eac434ed0c3be9257cc0ca144dd99c11cc8f1a49467a37d8e8002203c496c72253c528e6bc81c42e683aba974d46041a96ef7b00915c863eb2a702901 0x47 0x304402207ffb4da33f40cac839a43000a187bd76a1ee5bf95e46dc1534b38bb7bd0321db022038c078f29d1831f8eb68ffdc2634c654fb01c3467b6457b98ad220653bb2478501 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", "P2SH", "P2SH(2-of-3)"],
-["0x47 0x304402200001cae94b795baaafb05db38cf24cd75560cab2c36c91e29fac7d0fd2a723a3022058e2e56e568ce7c4b2b106210d114e1faa079407a6ed4154f230667c7d3583bc01", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "", "P2PK with too much R padding but no STRICTENC"],
-["0x48 0x304502206d01de7c2a40ac2bb1231ed97f3890a1782f421d4c28b97166deff317990288f0221005e720213b089355be2cf785d81a82c59307d30e1624f450ed9ca1ebbc11cca6d01", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "", "P2PK with too much S padding but no STRICTENC"],
-["0x47 0x30440220f3d8889602147d60d26c1d3b21b8db183eac02bf6d2fec1424c0ef377ca6fd7b02202bae8bfe39d00a432d4538a592e338b0ffc44c17d4b7056043d55063cf91f5ef01", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "", "P2PK with too little R padding but no STRICTENC"],
-["0x48 0x3045022021bf9184d94f208ac9f4757ebca9b1cbebf008cfc244fe5be1360b1b9aba0e92022100e55074f72f3a1bfddf2ea4ea7ba984f78822e136fe04c8f9c1363238e0233bd801", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "STRICTENC", "P2PK with high S but no LOW_S"],
-["0x48 0x304502205c3e81aaf2aad0673f349035b180eba783eba7797af91c979920dea6b17a16d6022100d1d46825c68da1b325f320a3503dad27bb818227f64a38d153554bfd360c0e5301", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "LOW_S", "P2PK with high S but no STRICTENC"],
-["0x01 0x01 0x47 0x3044022046ce33d1771b0127dd4c4cef8fdc3218ebdfa60e3793ed700292d8ebd93fb1f402201029d47a414db83e96e31443c2d8b552f971469c4800f5eff7df2f0648521aed01 0x47 0x304402205c53911ad55b054920043962bbda98cf6e57e2db1cd5611138251490baabaa8702201dc80dfceae6007e7772dc13ff6e7ca66a983cb017fe5d46d30118462d83bcf801 0x47 0x304402201937e44a4ec12364f9d32f9d25e7ecbc68aee9ef90069af80efef4c05f6ace9602206c515101c00c75710b32ff7ff8dbaf7c9a0be6e86ed14a0755b47626604f31fd01", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3 with nonzero dummy but no NULLDUMMY"],
+[
+ "0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501",
+ "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
+ "",
+ "P2PK"
+],
+[
+ "0x47 0x3044022069d40999786aeb2fd874f9eb2636461a062dc963471627ed8390a3a5f9556f640220350132a52415ce622f2aadd07f791c591500917ec1f8c5edbc5381ef7942534d01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508",
+ "DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG",
+ "",
+ "P2PKH"
+],
+[
+ "0x47 0x30440220519f2a6632ffa134c7811ea2819e9dcc951f0c7baf461f2dffdd09133f3b080a02203ec6bab5eb6619ed7f41b8701d7c6d70cfc83bb26c5c97f54b2ca6e304fc2bb581",
+ "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
+ "",
+ "P2PK anyonecanpay"
+],
+[
+ "0x47 0x30440220279dad2170ffb5639f0a1ea71fc462ee37d75d420d86f84c978bac523c09b7f20220683b2789f5c5528a9e0a0d78f6e40db3f616cf1adb5a5fdef117d5974795cfe201 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
+ "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL",
+ "P2SH",
+ "P2SH(P2PK)"
+],
+[
+ "0x47 0x3044022066acbfb5ac96b7cbf3f05a2aaf358c32438c45d1d7359dee9fc1ee636940735f02205606a03fd8cbf6a6fcbcba60c8abb1e385c0b5753cb57a97538159106fd3684e01 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
+ "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",
+ "",
+ "P2SH(P2PKH), bad sig but no VERIFY_P2SH"
+],
+[
+ "0 0x47 0x3044022004e791dd30a64c70e55e84e150c002af9feb3ce0ab1f20e86c53d1209003927502205a60453987fcd72aebaaacebc8ce4b15449cdd79e54cc82cefb83e69dbcfeabf01 0x47 0x304402201d021808ce93dd8574cc4f99ae4f11b44305528b0aecbd9f156f08315173643802200944a0ea5c884bd86180aef76d8b1e444860776b251e47d2d6c651a1c6f9930801 0x47 0x30440220446336d7b7de05ebb5683b82b05248ec7d78e88ae8d6125985f5776c887a4cf90220674ab2b2c2f954ba1cf35457d273c90d0c0c1c224d0ae128628740e81129486801",
+ "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
+ "",
+ "3-of-3"
+],
+[
+ "0 0x47 0x30440220288b06d057cf0eac434ed0c3be9257cc0ca144dd99c11cc8f1a49467a37d8e8002203c496c72253c528e6bc81c42e683aba974d46041a96ef7b00915c863eb2a702901 0x47 0x304402207ffb4da33f40cac839a43000a187bd76a1ee5bf95e46dc1534b38bb7bd0321db022038c078f29d1831f8eb68ffdc2634c654fb01c3467b6457b98ad220653bb2478501 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",
+ "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL",
+ "P2SH",
+ "P2SH(2-of-3)"
+],
+[
+ "0x47 0x30440220001fff8863c84c0efc8eea5bffb7f388313f966f23a00ad3c0acc30ff5339684022016e6d78f51a3a1c362745931ca40b24f71cba2903dbfe5a6d392a9189127d83701",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "",
+ "P2PK with too much R padding but no DERSIG"
+],
+[
+ "0x48 0x304502202323d56f293842b544cacedd06baafb999196dfa1c2975314848c158ac606655022100514bd98186b8a3a1cc87f4aff76aed797781389f13f50d87bf95b2df6e488fcc01",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "",
+ "P2PK with too much S padding but no DERSIG"
+],
+[
+ "0x47 0x30440220d31c24bb6c08a496e7698a08fd41975115d7b55bfaa31cb2d573e09481e59a6702206a691239996434076b78a4e1cf46fc8e993b468a9c77fb1832186aa8040a61a201",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "",
+ "P2PK with too little R padding but no DERSIG"
+],
+[
+ "0x47 0x30440220007c2cc7aef1801c2937447703c87ef2a3744209ad98da2abadd4ba8bb2e3ea00220503a275582c9f9e9ff30260c81b7f64b8b696f22105605cc8241fb76a797316201",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
+ "",
+ "P2PK NOT with bad sig with too much R padding but no DERSIG"
+],
+[
+ "0x48 0x3045022021bf9184d94f208ac9f4757ebca9b1cbebf008cfc244fe5be1360b1b9aba0e92022100e55074f72f3a1bfddf2ea4ea7ba984f78822e136fe04c8f9c1363238e0233bd801",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
+ "STRICTENC",
+ "P2PK with high S but no LOW_S"
+],
+[
+ "0x47 0x304402202163bc732c21b7de0251297d3c6c2ece182782e85fc5e19d6036f1130a79051e022033827811634924ebba68767537d78dd7bd9109ae2a89a60587927abdc25eb06401",
+ "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
+ "",
+ "P2PK with hybrid pubkey but no STRICTENC"
+],
+[
+ "0x47 0x3044022078033e4227aa05ded69d8da579966578e230d8a7fb44d5f1a0620c3853c24f78022006a2e3f4d872ac8dfdc529110aa37301d65a76255a4b6cce2992adacd4d2c4e201",
+ "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
+ "STRICTENC",
+ "P2PK NOT with hybrid pubkey"
+],
+[
+ "0x47 0x3044022078d6c447887e88dcbe1bc5b613645280df6f4e5935648bc226e9d91da71b3216022047d6b7ef0949b228fc1b359afb8d50500268711354298217b983c26970790c7601",
+ "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
+ "",
+ "P2PK NOT with invalid hybrid pubkey but no STRICTENC"
+],
+[
+ "0x47 0x304402207592427de20e315d644839754f2a5cca5b978b983a15e6da82109ede01722baa022032ceaf78590faa3f7743821e1b47b897ed1a57f6ee1c8a7519d23774d8de3c4401",
+ "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
+ "STRICTENC",
+ "P2PK NOT with invalid hybrid pubkey"
+],
+[
+ "0x47 0x304402204649e9517ef0377a8f8270bd423053fd98ddff62d74ea553e9579558abbb75e4022044a2b2344469c12e35ed898987711272b634733dd0f5e051288eceb04bd4669e05",
+ "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
+ "",
+ "P2PK with undefined hashtype but no STRICTENC"
+],
+[
+ "0x47 0x304402207f1cf1866a2df0bb4b8d84d0ade72aa3abb6aaab0639d608b23d9e10ead0c48202203caa97f22c3439443eea4b89f7f6729854df0f567a8184d6ecc6e8b6c68c3e9d05",
+ "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT",
+ "",
+ "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC"
+],
+[
+ "0x01 0x01 0x47 0x3044022046ce33d1771b0127dd4c4cef8fdc3218ebdfa60e3793ed700292d8ebd93fb1f402201029d47a414db83e96e31443c2d8b552f971469c4800f5eff7df2f0648521aed01 0x47 0x304402205c53911ad55b054920043962bbda98cf6e57e2db1cd5611138251490baabaa8702201dc80dfceae6007e7772dc13ff6e7ca66a983cb017fe5d46d30118462d83bcf801 0x47 0x304402201937e44a4ec12364f9d32f9d25e7ecbc68aee9ef90069af80efef4c05f6ace9602206c515101c00c75710b32ff7ff8dbaf7c9a0be6e86ed14a0755b47626604f31fd01",
+ "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
+ "",
+ "3-of-3 with nonzero dummy but no NULLDUMMY"
+],
+[
+ "0x01 0x01 0x47 0x30440220195038dbc6b2ae1199f86a6777824f7c5149789d85f655a3534a4422b8fba38c02204df9db87d2eb9fe06edc66870d9ac4c9ce673459f9d43cee0347ce4ffb02ee5a01 0x47 0x3044022010a45f30c6fa97a186eba9e6b595ab87d3dfcbf05dcaf1f1b8e3e7bf39515bb802203474e78d3d372e5f5c0f8c257ce8300c4bb8f37c51d4a894e11a91b5817da6ed01 0x47 0x30440220039cffd8e39850f95112662b1220b14b3c0d3d8a2772e13c947bfbf96345a64e02204154bfa77e2c0134d5434353bed82141e5da1cc479954aa288d5f0671480a04b01",
+ "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT",
+ "",
+ "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY"
+],
["The End"]
]
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 9e4669eba9..bad5c13ac2 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -253,6 +253,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
chainActive.Tip()->nHeight--;
SetMockTime(0);
+ mempool.clear();
BOOST_FOREACH(CTransaction *tx, txFirst)
delete tx;
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index cb37740068..5a2ec1cb31 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -82,19 +82,19 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys.clear();
keys += key[0],key[1]; // magic operator+= from boost.assign
s = sign_multisig(a_and_b, keys, txTo[0], 0);
- BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, flags));
+ BOOST_CHECK(VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0)));
for (int i = 0; i < 4; i++)
{
keys.clear();
keys += key[i];
s = sign_multisig(a_and_b, keys, txTo[0], 0);
- BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags), strprintf("a&b 1: %d", i));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0)), strprintf("a&b 1: %d", i));
keys.clear();
keys += key[1],key[i];
s = sign_multisig(a_and_b, keys, txTo[0], 0);
- BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags), strprintf("a&b 2: %d", i));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0)), strprintf("a&b 2: %d", i));
}
// Test a OR b:
@@ -104,16 +104,16 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys += 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, flags), strprintf("a|b: %d", i));
+ BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0)), strprintf("a|b: %d", i));
else
- BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, flags), strprintf("a|b: %d", i));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0)), strprintf("a|b: %d", i));
}
s.clear();
s << OP_0 << OP_0;
- BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags));
+ BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0)));
s.clear();
s << OP_0 << OP_1;
- BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags));
+ BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0)));
for (int i = 0; i < 4; i++)
@@ -123,9 +123,9 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys += key[i],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, flags), strprintf("escrow 1: %d %d", i, j));
+ BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0)), strprintf("escrow 1: %d %d", i, j));
else
- BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, flags), strprintf("escrow 2: %d %d", i, j));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0)), strprintf("escrow 2: %d %d", i, j));
}
}
diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp
index 1dc2a3d82f..91da0c4420 100644
--- a/src/test/rpc_wallet_tests.cpp
+++ b/src/test/rpc_wallet_tests.cpp
@@ -14,7 +14,7 @@
using namespace std;
using namespace json_spirit;
-extern Array createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL);
+extern Array createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL);
extern Value CallRPC(string args);
extern CWallet* pwalletMain;
@@ -53,10 +53,10 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig)
BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error);
BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error);
- string short1(address1Hex, address1Hex+sizeof(address1Hex)-2); // last byte missing
+ string short1(address1Hex, address1Hex + sizeof(address1Hex) - 2); // last byte missing
BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error);
- string short2(address1Hex+1, address1Hex+sizeof(address1Hex)); // first byte missing
+ string short2(address1Hex + 1, address1Hex + sizeof(address1Hex)); // first byte missing
BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error);
}
@@ -68,26 +68,30 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
LOCK2(cs_main, pwalletMain->cs_wallet);
CPubKey demoPubkey = pwalletMain->GenerateNewKey();
- CBitcoinAddress demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID()));
- Value retValue;
- string strAccount = "walletDemoAccount";
- string strPurpose = "receive";
- BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
- CWalletDB walletdb(pwalletMain->strWalletFile);
- CAccount account;
- account.vchPubKey = demoPubkey;
- pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose);
- walletdb.WriteAccount(strAccount, account);
- });
-
-
- /*********************************
- * setaccount
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ nullaccount"));
- BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error);
- /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X (33 chars) is an illegal address (should be 34 chars) */
- BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X nullaccount"), runtime_error);
+ CBitcoinAddress demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID()));
+ Value retValue;
+ string strAccount = "walletDemoAccount";
+ string strPurpose = "receive";
+ BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
+ CWalletDB walletdb(pwalletMain->strWalletFile);
+ CAccount account;
+ account.vchPubKey = demoPubkey;
+ pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose);
+ walletdb.WriteAccount(strAccount, account);
+ });
+
+ CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey();
+ CBitcoinAddress setaccountDemoAddress = CBitcoinAddress(CTxDestination(setaccountDemoPubkey.GetID()));
+
+ /*********************************
+ * setaccount
+ *********************************/
+ BOOST_CHECK_NO_THROW(CallRPC("setaccount " + setaccountDemoAddress.ToString() + " nullaccount"));
+ /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ is not owned by the test wallet. */
+ BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ nullaccount"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error);
+ /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X (33 chars) is an illegal address (should be 34 chars) */
+ BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X nullaccount"), runtime_error);
/*********************************
* listunspent
@@ -97,12 +101,12 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error);
- BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []"));
+ BOOST_CHECK_NO_THROW(r = CallRPC("listunspent 0 1 []"));
BOOST_CHECK(r.get_array().empty());
/*********************************
- * listreceivedbyaddress
- *********************************/
+ * listreceivedbyaddress
+ *********************************/
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress"));
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0"));
BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error);
@@ -111,8 +115,8 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error);
/*********************************
- * listreceivedbyaccount
- *********************************/
+ * listreceivedbyaccount
+ *********************************/
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount"));
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0"));
BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error);
@@ -121,59 +125,58 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error);
/*********************************
- * getrawchangeaddress
- *********************************/
+ * getrawchangeaddress
+ *********************************/
BOOST_CHECK_NO_THROW(CallRPC("getrawchangeaddress"));
/*********************************
- * getnewaddress
- *********************************/
+ * getnewaddress
+ *********************************/
BOOST_CHECK_NO_THROW(CallRPC("getnewaddress"));
BOOST_CHECK_NO_THROW(CallRPC("getnewaddress getnewaddress_demoaccount"));
/*********************************
- * getaccountaddress
- *********************************/
+ * getaccountaddress
+ *********************************/
BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress \"\""));
- BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress accountThatDoesntExists")); // Should generate a new account
- BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount));
- BOOST_CHECK(CBitcoinAddress(retValue.get_str()).Get() == demoAddress.Get());
-
- /*********************************
- * getaccount
- *********************************/
- BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC("getaccount " + demoAddress.ToString()));
-
- /*********************************
- * signmessage + verifymessage
- *********************************/
- BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + demoAddress.ToString() + " mymessage"));
- BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error);
- /* Should throw error because this address is not loaded in the wallet */
- BOOST_CHECK_THROW(CallRPC("signmessage 1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ mymessage"), runtime_error);
-
- /* missing arguments */
- BOOST_CHECK_THROW(CallRPC("verifymessage "+ demoAddress.ToString()), runtime_error);
- BOOST_CHECK_THROW(CallRPC("verifymessage "+ demoAddress.ToString() + " " + retValue.get_str()), runtime_error);
- /* Illegal address */
- BOOST_CHECK_THROW(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X " + retValue.get_str() + " mymessage"), runtime_error);
- /* wrong address */
- BOOST_CHECK(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ " + retValue.get_str() + " mymessage").get_bool() == false);
- /* Correct address and signature but wrong message */
- BOOST_CHECK(CallRPC("verifymessage "+ demoAddress.ToString() + " " + retValue.get_str() + " wrongmessage").get_bool() == false);
- /* Correct address, message and signature*/
- BOOST_CHECK(CallRPC("verifymessage "+ demoAddress.ToString() + " " + retValue.get_str() + " mymessage").get_bool() == true);
-
- /*********************************
- * getaddressesbyaccount
- *********************************/
- BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error);
- BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount));
- Array arr = retValue.get_array();
- BOOST_CHECK(arr.size() > 0);
- BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get());
+ BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress accountThatDoesntExists")); // Should generate a new account
+ BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount));
+ BOOST_CHECK(CBitcoinAddress(retValue.get_str()).Get() == demoAddress.Get());
+ /*********************************
+ * getaccount
+ *********************************/
+ BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC("getaccount " + demoAddress.ToString()));
+
+ /*********************************
+ * signmessage + verifymessage
+ *********************************/
+ BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + demoAddress.ToString() + " mymessage"));
+ BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error);
+ /* Should throw error because this address is not loaded in the wallet */
+ BOOST_CHECK_THROW(CallRPC("signmessage 1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ mymessage"), runtime_error);
+
+ /* missing arguments */
+ BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString()), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str()), runtime_error);
+ /* Illegal address */
+ BOOST_CHECK_THROW(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X " + retValue.get_str() + " mymessage"), runtime_error);
+ /* wrong address */
+ BOOST_CHECK(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ " + retValue.get_str() + " mymessage").get_bool() == false);
+ /* Correct address and signature but wrong message */
+ BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " wrongmessage").get_bool() == false);
+ /* Correct address, message and signature*/
+ BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " mymessage").get_bool() == true);
+
+ /*********************************
+ * getaddressesbyaccount
+ *********************************/
+ BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error);
+ BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount));
+ Array arr = retValue.get_array();
+ BOOST_CHECK(arr.size() > 0);
+ BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get());
}
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index e6cf00c2d0..f8361a0dc8 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -42,7 +42,7 @@ 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 ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE);
+ return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, SignatureChecker(txTo, 0));
}
@@ -113,7 +113,7 @@ BOOST_AUTO_TEST_CASE(sign)
{
CScript sigSave = txTo[i].vin[0].scriptSig;
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
- bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC)();
+ bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false)();
if (i == j)
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
else
@@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
{
LOCK(cs_main);
CCoinsView coinsDummy;
- CCoinsViewCache coins(coinsDummy);
+ CCoinsViewCache coins(&coinsDummy);
CBasicKeyStore keystore;
CKey key[6];
vector<CPubKey> keys;
@@ -312,8 +312,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txFrom.vout[6].scriptPubKey = GetScriptForDestination(twentySigops.GetID());
txFrom.vout[6].nValue = 6000;
-
- coins.SetCoins(txFrom.GetHash(), CCoins(txFrom, 0));
+ coins.ModifyCoins(txFrom.GetHash())->FromTx(txFrom, 0);
CMutableTransaction txTo;
txTo.vout.resize(1);
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 7f09b3daa1..a4b0212494 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -34,6 +34,9 @@ using namespace std;
using namespace json_spirit;
using namespace boost::algorithm;
+// Uncomment if you want to output updated JSON tests.
+// #define UPDATE_JSON_TESTS
+
static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
unsigned int ParseScriptFlags(string strFlags);
@@ -70,7 +73,7 @@ CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey)
return txCredit;
}
-CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CTransaction& txCredit)
+CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit)
{
CMutableTransaction txSpend;
txSpend.nVersion = 1;
@@ -89,7 +92,7 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CTr
void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message)
{
- BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)), 0, flags) == expect, message);
+ BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, SignatureChecker(BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)), 0)) == expect, message);
}
namespace
@@ -239,14 +242,15 @@ public:
return *this;
}
- operator std::string()
+ Array GetJSON()
{
DoPush();
- return "[\"" +
- FormatScript(spendTx.vin[0].scriptSig) + "\", \"" +
- FormatScript(creditTx.vout[0].scriptPubKey) + "\", \"" +
- FormatScriptFlags(flags) + "\", \"" +
- comment + "\"],\n";
+ Array array;
+ array.push_back(FormatScript(spendTx.vin[0].scriptSig));
+ array.push_back(FormatScript(creditTx.vout[0].scriptPubKey));
+ array.push_back(FormatScriptFlags(flags));
+ array.push_back(comment);
+ return array;
}
std::string GetComment()
@@ -316,40 +320,87 @@ BOOST_AUTO_TEST_CASE(script_build)
).Num(0).PushSig(keys.key1).Num(0).PushRedeem());
good.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG,
- "P2PK with too much R padding but no STRICTENC", 0
+ "P2PK with too much R padding but no DERSIG", 0
).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
bad.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG,
- "P2PK with too much R padding", SCRIPT_VERIFY_STRICTENC
+ "P2PK with too much R padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
good.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG,
- "P2PK with too much S padding but no STRICTENC", 0
+ "P2PK with too much S padding but no DERSIG", 0
).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100"));
bad.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG,
- "P2PK with too much S padding", SCRIPT_VERIFY_STRICTENC
+ "P2PK with too much S padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100"));
good.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG,
- "P2PK with too little R padding but no STRICTENC", 0
+ "P2PK with too little R padding but no DERSIG", 0
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG,
- "P2PK with too little R padding", SCRIPT_VERIFY_STRICTENC
+ "P2PK with too little R padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
+ good.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG << OP_NOT,
+ "P2PK NOT with bad sig with too much R padding but no DERSIG", 0
+ ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10));
+ bad.push_back(TestBuilder(CScript() << 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));
+ bad.push_back(TestBuilder(CScript() << 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"));
+ bad.push_back(TestBuilder(CScript() << 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"));
good.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG,
- "P2PK with high S but no LOW_S", SCRIPT_VERIFY_STRICTENC
- ).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
- good.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG,
- "P2PK with high S but no STRICTENC", SCRIPT_VERIFY_LOW_S
+ "P2PK with high S but no LOW_S", 0
).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
bad.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG,
- "P2PK with high S", SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC
+ "P2PK with high S", SCRIPT_VERIFY_LOW_S
).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
+ good.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG,
+ "P2PK with hybrid pubkey but no STRICTENC", 0
+ ).PushSig(keys.key0, SIGHASH_ALL));
+ bad.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG,
+ "P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC
+ ).PushSig(keys.key0, SIGHASH_ALL));
+ bad.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG << OP_NOT,
+ "P2PK NOT with hybrid pubkey but no STRICTENC", 0
+ ).PushSig(keys.key0, SIGHASH_ALL));
+ good.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG << OP_NOT,
+ "P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC
+ ).PushSig(keys.key0, SIGHASH_ALL));
+ good.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG << OP_NOT,
+ "P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0
+ ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10));
+ good.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG << OP_NOT,
+ "P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC
+ ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10));
+
+ good.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG,
+ "P2PK with undefined hashtype but no STRICTENC", 0
+ ).PushSig(keys.key1, 5));
+ bad.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG,
+ "P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC
+ ).PushSig(keys.key1, 5));
+ good.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG << OP_NOT,
+ "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0
+ ).PushSig(keys.key1, 5).DamagePush(10));
+ bad.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG << OP_NOT,
+ "P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC
+ ).PushSig(keys.key1, 5).DamagePush(10));
+
good.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << keys.pubkey2C << OP_3 << OP_CHECKMULTISIG,
"3-of-3 with nonzero dummy but no NULLDUMMY", 0
).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2));
bad.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << 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));
+ good.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << keys.pubkey2C << OP_3 << OP_CHECKMULTISIG << OP_NOT,
+ "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY", 0
+ ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10));
+ bad.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << 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));
std::map<std::string, Array> tests_good;
std::map<std::string, Array> tests_bad;
@@ -377,18 +428,30 @@ BOOST_AUTO_TEST_CASE(script_build)
BOOST_FOREACH(TestBuilder& test, good) {
test.Test(true);
- BOOST_CHECK_MESSAGE(tests_good.count(test.GetComment()) > 0, "Missing auto script_valid test: " + test.GetComment());
- BOOST_CHECK_MESSAGE(ParseScript(tests_good[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_valid test: " + test.GetComment());
- strGood += test;
+ if (tests_good.count(test.GetComment()) == 0) {
+#ifndef UPDATE_JSON_TESTS
+ BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment());
+#endif
+ strGood += write_string(Value(test.GetJSON()), true) + ",\n";
+ } else {
+ BOOST_CHECK_MESSAGE(ParseScript(tests_good[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_valid test: " + test.GetComment());
+ strGood += write_string(Value(tests_good[test.GetComment()]), true) + ",\n";
+ }
}
BOOST_FOREACH(TestBuilder& test, bad) {
test.Test(false);
- BOOST_CHECK_MESSAGE(tests_bad.count(test.GetComment()) > 0, "Missing auto script_invalid test: " + test.GetComment());
- BOOST_CHECK_MESSAGE(ParseScript(tests_bad[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_invalid test: " + test.GetComment());
- strBad += test;
+ if (tests_bad.count(test.GetComment()) == 0) {
+#ifndef UPDATE_JSON_TESTS
+ BOOST_CHECK_MESSAGE(false, "Missing auto script_invalid test: " + test.GetComment());
+#endif
+ strBad += write_string(Value(test.GetJSON()), true) + ",\n";
+ } else {
+ BOOST_CHECK_MESSAGE(ParseScript(tests_bad[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_invalid test: " + test.GetComment());
+ strBad += write_string(Value(tests_bad[test.GetComment()]), true) + ",\n";
+ }
}
-#if 0
+#ifdef UPDATE_JSON_TESTS
FILE* valid = fopen("script_valid.json.gen", "w");
fputs(strGood.c_str(), valid);
fclose(valid);
@@ -464,18 +527,18 @@ BOOST_AUTO_TEST_CASE(script_PushData)
static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a };
vector<vector<unsigned char> > directStack;
- BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, true));
+ BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), true, BaseSignatureChecker()));
vector<vector<unsigned char> > pushdata1Stack;
- BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, true));
+ BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), true, BaseSignatureChecker()));
BOOST_CHECK(pushdata1Stack == directStack);
vector<vector<unsigned char> > pushdata2Stack;
- BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, true));
+ BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), true, BaseSignatureChecker()));
BOOST_CHECK(pushdata2Stack == directStack);
vector<vector<unsigned char> > pushdata4Stack;
- BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, true));
+ BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), true, BaseSignatureChecker()));
BOOST_CHECK(pushdata4Stack == directStack);
}
@@ -521,27 +584,19 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
CScript scriptPubKey12;
scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG;
- CMutableTransaction txFrom12;
- txFrom12.vout.resize(1);
- txFrom12.vout[0].scriptPubKey = scriptPubKey12;
-
- CMutableTransaction 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);
+ CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
- BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, flags));
+ BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0)));
txTo12.vout[0].nValue = 2;
- BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, flags));
+ BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0)));
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
- BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, flags));
+ BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, SignatureChecker(txTo12, 0)));
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
- BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, flags));
+ BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0)));
}
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
@@ -555,60 +610,52 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
CScript scriptPubKey23;
scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG;
- CMutableTransaction txFrom23;
- txFrom23.vout.resize(1);
- txFrom23.vout[0].scriptPubKey = scriptPubKey23;
-
- CMutableTransaction 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);
+ CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), txFrom23);
std::vector<CKey> keys;
keys.push_back(key1); keys.push_back(key2);
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, flags));
+ BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0)));
keys.clear();
keys.push_back(key1); keys.push_back(key3);
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, flags));
+ BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0)));
keys.clear();
keys.push_back(key2); keys.push_back(key3);
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, flags));
+ BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0)));
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, flags));
+ BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0)));
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, flags));
+ BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0)));
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, flags));
+ BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0)));
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, flags));
+ BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, SignatureChecker(txTo23, 0)));
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, flags));
+ BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, SignatureChecker(txTo23, 0)));
keys.clear(); // Must have signatures
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, flags));
+ BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, SignatureChecker(txTo23, 0)));
}
BOOST_AUTO_TEST_CASE(script_combineSigs)
@@ -626,17 +673,10 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
keystore.AddKey(key);
}
- CMutableTransaction txFrom;
- txFrom.vout.resize(1);
- txFrom.vout[0].scriptPubKey = GetScriptForDestination(keys[0].GetPubKey().GetID());
+ CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID()));
+ CMutableTransaction txTo = BuildSpendingTransaction(CScript(), txFrom);
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
- CMutableTransaction 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;
CScript empty;
CScript combined = CombineSignatures(scriptPubKey, txTo, 0, empty, empty);
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 68fad8d038..afd63d2717 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -31,7 +31,7 @@ struct TestingSetup {
TestingSetup() {
fPrintToDebugLog = false; // don't want to write to debug.log file
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(CBaseChainParams::UNITTEST);
noui_connect();
#ifdef ENABLE_WALLET
bitdb.MakeMock();
@@ -41,7 +41,7 @@ struct TestingSetup {
mapArgs["-datadir"] = pathTemp.string();
pblocktree = new CBlockTreeDB(1 << 20, true);
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
- pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
+ pcoinsTip = new CCoinsViewCache(pcoinsdbview);
InitBlockIndex();
#ifdef ENABLE_WALLET
bool fFirstRun;
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 83116b51e5..18cb8f3d1b 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -27,11 +27,11 @@ using namespace boost::algorithm;
// In script_tests.cpp
extern Array read_json(const std::string& jsondata);
-// Note how NOCACHE is not included as it is a runtime-only flag.
static std::map<string, unsigned int> 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("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY);
@@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- tx, i, verify_flags),
+ verify_flags, SignatureChecker(tx, i)),
strTest);
}
}
@@ -212,7 +212,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- tx, i, verify_flags);
+ verify_flags, SignatureChecker(tx, i));
}
BOOST_CHECK_MESSAGE(!fValid, strTest);
@@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
// paid to a TX_PUBKEYHASH.
//
static std::vector<CMutableTransaction>
-SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsView & coinsRet)
+SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
{
std::vector<CMutableTransaction> dummyTransactions;
dummyTransactions.resize(2);
@@ -262,14 +262,14 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsView & coinsRet)
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;
- coinsRet.SetCoins(dummyTransactions[0].GetHash(), CCoins(dummyTransactions[0], 0));
+ coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0);
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());
- coinsRet.SetCoins(dummyTransactions[1].GetHash(), CCoins(dummyTransactions[1], 0));
+ coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0);
return dummyTransactions;
}
@@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(test_Get)
{
CBasicKeyStore keystore;
CCoinsView coinsDummy;
- CCoinsViewCache coins(coinsDummy);
+ CCoinsViewCache coins(&coinsDummy);
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
CMutableTransaction t1;
@@ -313,7 +313,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
LOCK(cs_main);
CBasicKeyStore keystore;
CCoinsView coinsDummy;
- CCoinsViewCache coins(coinsDummy);
+ CCoinsViewCache coins(&coinsDummy);
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
CMutableTransaction t;
diff --git a/src/txdb.cpp b/src/txdb.cpp
index d5f424fabd..cb9f150011 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -33,12 +33,6 @@ bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
return db.Read(make_pair('c', txid), coins);
}
-bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) {
- CLevelDBBatch batch;
- BatchWriteCoins(batch, txid, coins);
- return db.WriteBatch(batch);
-}
-
bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
return db.Exists(make_pair('c', txid));
}
@@ -50,24 +44,23 @@ uint256 CCoinsViewDB::GetBestBlock() const {
return hashBestChain;
}
-bool CCoinsViewDB::SetBestBlock(const uint256 &hashBlock) {
- CLevelDBBatch batch;
- BatchWriteHashBestChain(batch, hashBlock);
- return db.WriteBatch(batch);
-}
-
bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
- LogPrint("coindb", "Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
-
CLevelDBBatch batch;
+ size_t count = 0;
+ size_t changed = 0;
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
- BatchWriteCoins(batch, it->first, it->second);
+ if (it->second.flags & CCoinsCacheEntry::DIRTY) {
+ BatchWriteCoins(batch, it->first, it->second.coins);
+ changed++;
+ }
+ count++;
CCoinsMap::iterator itOld = it++;
mapCoins.erase(itOld);
}
if (hashBlock != uint256(0))
BatchWriteHashBestChain(batch, hashBlock);
+ LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
return db.WriteBatch(batch);
}
diff --git a/src/txdb.h b/src/txdb.h
index f0b6b9e1dd..8f2bd9af4d 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -33,10 +33,8 @@ public:
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
bool GetCoins(const uint256 &txid, CCoins &coins) const;
- bool SetCoins(const uint256 &txid, const CCoins &coins);
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
- bool SetBestBlock(const uint256 &hashBlock);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
bool GetStats(CCoinsStats &stats) const;
};
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index d923c2204a..fa1802ad31 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -631,7 +631,7 @@ void CTxMemPool::ClearPrioritisation(const uint256 hash)
}
-CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
+CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
// If an entry in the mempool exists, always return that one, as it's guaranteed to never
diff --git a/src/txmempool.h b/src/txmempool.h
index c35ea52d4e..c63fd6f590 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -144,7 +144,7 @@ protected:
CTxMemPool &mempool;
public:
- CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn);
+ CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn);
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
};
diff --git a/src/util.h b/src/util.h
index fb1d3eacb5..4b2415278b 100644
--- a/src/util.h
+++ b/src/util.h
@@ -14,7 +14,6 @@
#include "config/bitcoin-config.h"
#endif
-#include "amount.h"
#include "compat.h"
#include "tinyformat.h"
#include "utiltime.h"
diff --git a/src/wallet.cpp b/src/wallet.cpp
index b20b0007ce..026c53aa2e 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -15,6 +15,8 @@
#include "util.h"
#include "utilmoneystr.h"
+#include <assert.h>
+
#include <boost/algorithm/string/replace.hpp>
#include <boost/thread.hpp>
@@ -426,17 +428,25 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
if (fFileBacked)
{
+ assert(!pwalletdbEncryption);
pwalletdbEncryption = new CWalletDB(strWalletFile);
- if (!pwalletdbEncryption->TxnBegin())
+ if (!pwalletdbEncryption->TxnBegin()) {
+ delete pwalletdbEncryption;
+ pwalletdbEncryption = NULL;
return false;
+ }
pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
}
if (!EncryptKeys(vMasterKey))
{
- if (fFileBacked)
+ if (fFileBacked) {
pwalletdbEncryption->TxnAbort();
- exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
+ delete pwalletdbEncryption;
+ }
+ // We now probably have half of our keys encrypted in memory, and half not...
+ // die and let the user reload their unencrypted wallet.
+ assert(false);
}
// Encryption was introduced in version 0.4.0
@@ -444,8 +454,12 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
if (fFileBacked)
{
- if (!pwalletdbEncryption->TxnCommit())
- exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
+ if (!pwalletdbEncryption->TxnCommit()) {
+ delete pwalletdbEncryption;
+ // We now have keys encrypted in memory, but no on disk...
+ // die to avoid confusion and let the user reload their unencrypted wallet.
+ assert(false);
+ }
delete pwalletdbEncryption;
pwalletdbEncryption = NULL;
@@ -1068,7 +1082,7 @@ CAmount CWallet::GetWatchOnlyBalance() const
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
}
-
+
return nTotal;
}
diff --git a/src/wallet.h b/src/wallet.h
index f3fffb2253..58e285b7eb 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -143,6 +143,7 @@ public:
{
SetNull();
}
+
CWallet(std::string strWalletFileIn)
{
SetNull();
@@ -150,6 +151,13 @@ public:
strWalletFile = strWalletFileIn;
fFileBacked = true;
}
+
+ ~CWallet()
+ {
+ delete pwalletdbEncryption;
+ pwalletdbEncryption = NULL;
+ }
+
void SetNull()
{
nWalletVersion = FEATURE_BASE;
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index 3e5a664a5d..e09bb8d1b2 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -15,11 +15,11 @@
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
+#include <boost/scoped_ptr.hpp>
#include <boost/thread.hpp>
-using namespace std;
using namespace boost;
-
+using namespace std;
static uint64_t nAccountingEntryNumber = 0;
@@ -918,7 +918,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys)
LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
bool fSuccess = allOK;
- Db* pdbCopy = new Db(&dbenv.dbenv, 0);
+ boost::scoped_ptr<Db> pdbCopy(new Db(&dbenv.dbenv, 0));
int ret = pdbCopy->open(NULL, // Txn pointer
filename.c_str(), // Filename
"main", // Logical db name
@@ -959,7 +959,6 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys)
}
ptxn->commit(0);
pdbCopy->close(0);
- delete pdbCopy;
return fSuccess;
}