aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml23
-rwxr-xr-xautogen.sh3
-rw-r--r--build-aux/m4/bitcoin_qt.m432
-rw-r--r--configure.ac38
-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
-rw-r--r--depends/config.site.in4
-rw-r--r--depends/packages/native_comparisontool.mk6
-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.qt.include2
-rw-r--r--src/Makefile.qttest.include2
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/alert.cpp37
-rw-r--r--src/alert.h3
-rw-r--r--src/bitcoin-tx.cpp22
-rw-r--r--src/chainparams.cpp75
-rw-r--r--src/chainparams.h6
-rw-r--r--src/checkpoints.cpp81
-rw-r--r--src/checkpoints.h12
-rw-r--r--src/coins.cpp117
-rw-r--r--src/coins.h81
-rw-r--r--src/init.cpp16
-rw-r--r--src/main.cpp168
-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/qt/bitcoin.cpp25
-rw-r--r--src/qt/bitcoingui.cpp57
-rw-r--r--src/qt/bitcoingui.h7
-rw-r--r--src/qt/bitcoinstrings.cpp16
-rw-r--r--src/qt/locale/bitcoin_en.ts346
-rw-r--r--src/qt/networkstyle.cpp47
-rw-r--r--src/qt/networkstyle.h33
-rw-r--r--src/qt/optionsmodel.cpp2
-rw-r--r--src/qt/splashscreen.cpp26
-rw-r--r--src/qt/splashscreen.h4
-rw-r--r--src/rpcblockchain.cpp2
-rw-r--r--src/rpcmining.cpp2
-rw-r--r--src/rpcmisc.cpp2
-rw-r--r--src/rpcnet.cpp42
-rw-r--r--src/rpcrawtransaction.cpp29
-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/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/multisig_tests.cpp18
-rw-r--r--src/test/script_P2SH_tests.cpp9
-rw-r--r--src/test/script_tests.cpp147
-rw-r--r--src/test/test_bitcoin.cpp2
-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/wallet.cpp26
-rw-r--r--src/wallet.h8
-rw-r--r--src/walletdb.cpp7
76 files changed, 1881 insertions, 1120 deletions
diff --git a/.travis.yml b/.travis.yml
index eae07ead8e..94d1c15f80 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,8 +1,8 @@
# errata:
# - A travis bug causes caches to trample eachother when using the same
# compiler key (which we don't use anyway). This is worked around for now by
-# using the phony compilers "true X". These can be removed when the travis
-# bug is fixed. See: https://github.com/travis-ci/casher/issues/6
+# replacing the "compilers" with a build name prefixed by the no-op ":"
+# command. See: https://github.com/travis-ci/casher/issues/6
os: linux
language: cpp
@@ -24,19 +24,19 @@ cache:
matrix:
fast_finish: true
include:
- - compiler: "true 1"
+ - compiler: ": ARM"
env: HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf" DEP_OPTS="NO_QT=1" GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat"
- - compiler: "true 2"
+ - compiler: ": bitcoind"
env: HOST=x86_64-unknown-linux-gnu DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat CPPFLAGS=-DDEBUG_LOCKORDER"
- - compiler: "true 3"
+ - compiler: ": No wallet"
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"
- - compiler: "true 5"
+ - compiler: ": 32-bit + dash"
+ 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: ": Cross-Mac"
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"
+ - compiler: ": Win64"
env: HOST=x86_64-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev wine" RUN_TESTS=true GOAL="deploy"
- - compiler: "true 7"
+ - compiler: ": Win32"
env: HOST=i686-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev wine" RUN_TESTS=true GOAL="deploy"
install:
- if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi
@@ -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 71b1484894..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"
@@ -196,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
],[
@@ -291,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
@@ -304,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
@@ -358,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
@@ -373,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
])
@@ -385,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 abf9f39e65..90aa112421 100644
--- a/configure.ac
+++ b/configure.ac
@@ -240,7 +240,7 @@ case $host in
AC_CHECK_PROG([BREW],brew, brew)
if test x$BREW = xbrew; then
- dnl These Homebrew packages may be bottled, meaning that they won't be found
+ 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
@@ -250,14 +250,16 @@ case $host in
bdb_prefix=`$BREW --prefix berkeley-db4 2>/dev/null`
qt5_prefix=`$BREW --prefix qt5 2>/dev/null`
if test x$openssl_prefix != x; then
- export PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
+ 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
- export PKG_CONFIG_PATH="$qt5_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
+ PKG_CONFIG_PATH="$qt5_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
+ export PKG_CONFIG_PATH
fi
fi
else
@@ -287,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)
@@ -295,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"
@@ -519,7 +521,7 @@ if test x$use_tests = xyes; then
dnl Determine if -DBOOST_TEST_DYN_LINK is needed
AC_MSG_CHECKING([for dynamic linked boost test])
TEMP_LIBS="$LIBS"
- LIBS="$LIBS $BOOST_UNIT_TEST_FRAMEWORK_LIB"
+ LIBS="$LIBS $BOOST_LDFLAGS $BOOST_UNIT_TEST_FRAMEWORK_LIB"
TEMP_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
AC_LINK_IFELSE([AC_LANG_SOURCE([
@@ -607,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
@@ -721,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)
@@ -735,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
@@ -770,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/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/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/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.qt.include b/src/Makefile.qt.include
index 1ea039adb3..872a0cf1c5 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -178,6 +178,7 @@ BITCOIN_QT_H = \
qt/macdockiconhandler.h \
qt/macnotificationhandler.h \
qt/monitoreddatamapper.h \
+ qt/networkstyle.h \
qt/notificator.h \
qt/openuridialog.h \
qt/optionsdialog.h \
@@ -269,6 +270,7 @@ BITCOIN_QT_CPP = \
qt/guiutil.cpp \
qt/intro.cpp \
qt/monitoreddatamapper.cpp \
+ qt/networkstyle.cpp \
qt/notificator.cpp \
qt/optionsdialog.cpp \
qt/optionsmodel.cpp \
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index 2cba5b7e1e..23375bef82 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -13,7 +13,7 @@ TEST_QT_H = \
qt/test/paymentservertests.h
qt_test_test_bitcoin_qt_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
- $(QT_INCLUDES) $(QT_TEST_INCLUDES)
+ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
qt_test_test_bitcoin_qt_SOURCES = \
qt/test/test_main.cpp \
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/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 31c67715c8..f2a14b8293 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -44,6 +44,57 @@ static void convertSeed6(std::vector<CAddress> &vSeedsOut, const SeedSpec6 *data
}
}
+ // What makes a good checkpoint block?
+ // + Is surrounded by blocks with reasonable timestamps
+ // (no blocks before with a timestamp after, none after with
+ // timestamp before)
+ // + Contains no strange transactions
+static Checkpoints::MapCheckpoints mapCheckpoints =
+ boost::assign::map_list_of
+ ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
+ ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
+ ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
+ (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
+ (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
+ (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
+ (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"))
+ (210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"))
+ (216116, uint256("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e"))
+ (225430, uint256("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932"))
+ (250000, uint256("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214"))
+ (279000, uint256("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40"))
+ (295000, uint256("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983"))
+ ;
+static const Checkpoints::CCheckpointData data = {
+ &mapCheckpoints,
+ 1397080064, // * UNIX timestamp of last checkpoint block
+ 36544669, // * total number of transactions between genesis and last checkpoint
+ // (the tx=... number in the SetBestChain debug.log lines)
+ 60000.0 // * estimated number of transactions per day after checkpoint
+ };
+
+static Checkpoints::MapCheckpoints mapCheckpointsTestnet =
+ boost::assign::map_list_of
+ ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
+ ;
+static const Checkpoints::CCheckpointData dataTestnet = {
+ &mapCheckpointsTestnet,
+ 1337966069,
+ 1488,
+ 300
+ };
+
+static Checkpoints::MapCheckpoints mapCheckpointsRegtest =
+ boost::assign::map_list_of
+ ( 0, uint256("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"))
+ ;
+static const Checkpoints::CCheckpointData dataRegtest = {
+ &mapCheckpointsRegtest,
+ 0,
+ 0,
+ 0
+ };
+
class CMainParams : public CChainParams {
public:
CMainParams() {
@@ -116,6 +167,12 @@ public:
fRequireStandard = true;
fMineBlocksOnDemand = false;
fSkipProofOfWorkCheck = false;
+ fTestnetToBeDeprecatedFieldRPC = false;
+ }
+
+ const Checkpoints::CCheckpointData& Checkpoints() const
+ {
+ return data;
}
};
static CMainParams mainParams;
@@ -172,6 +229,11 @@ public:
fAllowMinDifficultyBlocks = true;
fRequireStandard = false;
fMineBlocksOnDemand = false;
+ fTestnetToBeDeprecatedFieldRPC = true;
+ }
+ const Checkpoints::CCheckpointData& Checkpoints() const
+ {
+ return dataTestnet;
}
};
static CTestNetParams testNetParams;
@@ -211,6 +273,11 @@ public:
fAllowMinDifficultyBlocks = true;
fRequireStandard = false;
fMineBlocksOnDemand = true;
+ fTestnetToBeDeprecatedFieldRPC = false;
+ }
+ const Checkpoints::CCheckpointData& Checkpoints() const
+ {
+ return dataRegtest;
}
};
static CRegTestParams regTestParams;
@@ -233,7 +300,13 @@ public:
fAllowMinDifficultyBlocks = false;
fMineBlocksOnDemand = true;
}
-public:
+
+ const Checkpoints::CCheckpointData& Checkpoints() const
+ {
+ // UnitTest share the same checkpoints as MAIN
+ return data;
+ }
+
// Published setters to allow changing values in unit test cases
virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) { nSubsidyHalvingInterval=anSubsidyHalvingInterval; }
virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority) { nEnforceBlockUpgradeMajority=anEnforceBlockUpgradeMajority; }
diff --git a/src/chainparams.h b/src/chainparams.h
index 50441a89f3..f157419bb2 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -8,6 +8,7 @@
#include "core.h"
#include "chainparamsbase.h"
+#include "checkpoints.h"
#include "protocol.h"
#include "uint256.h"
@@ -71,12 +72,14 @@ public:
/* Make miner stop after a block is found. In RPC, don't return
* until nGenProcLimit blocks are generated */
bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
- CBaseChainParams::Network NetworkID() const { return networkID; }
+ /* In the future use NetworkIDString() for RPC fields */
+ bool TestnetToBeDeprecatedFieldRPC() const { return fTestnetToBeDeprecatedFieldRPC; }
/* Return the BIP70 network string (main, test or regtest) */
std::string NetworkIDString() const { return strNetworkID; }
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
const std::vector<CAddress>& FixedSeeds() const { return vFixedSeeds; }
+ virtual const Checkpoints::CCheckpointData& Checkpoints() const = 0;
protected:
CChainParams() {}
@@ -106,6 +109,7 @@ protected:
bool fRequireStandard;
bool fMineBlocksOnDemand;
bool fSkipProofOfWorkCheck;
+ bool fTestnetToBeDeprecatedFieldRPC;
};
/** Modifiable parameters interface is used by test cases to adapt the parameters in order
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 9a6bc05e63..fbde47339d 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -4,18 +4,16 @@
#include "checkpoints.h"
+#include "chainparams.h"
#include "main.h"
#include "uint256.h"
#include <stdint.h>
-#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>
namespace Checkpoints {
- typedef std::map<int, uint256> MapCheckpoints;
-
// How many times we expect transactions after the last checkpoint to
// be slower. This number is a compromise, as it can't be accurate for
// every system. When reindexing from a fast disk with a slow CPU, it
@@ -23,83 +21,14 @@ namespace Checkpoints {
// fast multicore CPU, it won't be much higher than 1.
static const double SIGCHECK_VERIFICATION_FACTOR = 5.0;
- struct CCheckpointData {
- const MapCheckpoints *mapCheckpoints;
- int64_t nTimeLastCheckpoint;
- int64_t nTransactionsLastCheckpoint;
- double fTransactionsPerDay;
- };
-
bool fEnabled = true;
- // What makes a good checkpoint block?
- // + Is surrounded by blocks with reasonable timestamps
- // (no blocks before with a timestamp after, none after with
- // timestamp before)
- // + Contains no strange transactions
- static MapCheckpoints mapCheckpoints =
- boost::assign::map_list_of
- ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
- ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
- ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
- (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
- (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
- (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
- (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"))
- (210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"))
- (216116, uint256("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e"))
- (225430, uint256("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932"))
- (250000, uint256("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214"))
- (279000, uint256("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40"))
- (295000, uint256("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983"))
- ;
- static const CCheckpointData data = {
- &mapCheckpoints,
- 1397080064, // * UNIX timestamp of last checkpoint block
- 36544669, // * total number of transactions between genesis and last checkpoint
- // (the tx=... number in the SetBestChain debug.log lines)
- 60000.0 // * estimated number of transactions per day after checkpoint
- };
-
- static MapCheckpoints mapCheckpointsTestnet =
- boost::assign::map_list_of
- ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
- ;
- static const CCheckpointData dataTestnet = {
- &mapCheckpointsTestnet,
- 1337966069,
- 1488,
- 300
- };
-
- static MapCheckpoints mapCheckpointsRegtest =
- boost::assign::map_list_of
- ( 0, uint256("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"))
- ;
- static const CCheckpointData dataRegtest = {
- &mapCheckpointsRegtest,
- 0,
- 0,
- 0
- };
-
- const CCheckpointData &Checkpoints() {
- if (Params().NetworkID() == CBaseChainParams::TESTNET)
- 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;
- }
-
bool CheckBlock(int nHeight, const uint256& hash)
{
if (!fEnabled)
return true;
- const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
+ const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints;
MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
if (i == checkpoints.end()) return true;
@@ -119,7 +48,7 @@ namespace Checkpoints {
// Work is defined as: 1.0 per transaction before the last checkpoint, and
// fSigcheckVerificationFactor per transaction after.
- const CCheckpointData &data = Checkpoints();
+ const CCheckpointData &data = Params().Checkpoints();
if (pindex->nChainTx <= data.nTransactionsLastCheckpoint) {
double nCheapBefore = pindex->nChainTx;
@@ -143,7 +72,7 @@ namespace Checkpoints {
if (!fEnabled)
return 0;
- const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
+ const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints;
return checkpoints.rbegin()->first;
}
@@ -153,7 +82,7 @@ namespace Checkpoints {
if (!fEnabled)
return NULL;
- const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
+ const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints;
BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
{
diff --git a/src/checkpoints.h b/src/checkpoints.h
index fca046559a..b5b620fa6b 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -5,16 +5,26 @@
#ifndef BITCOIN_CHECKPOINT_H
#define BITCOIN_CHECKPOINT_H
+#include "uint256.h"
+
#include <map>
class CBlockIndex;
-class uint256;
/** Block-chain checkpoints are compiled-in sanity checks.
* They are updated every release or three.
*/
namespace Checkpoints
{
+typedef std::map<int, uint256> MapCheckpoints;
+
+struct CCheckpointData {
+ const MapCheckpoints *mapCheckpoints;
+ int64_t nTimeLastCheckpoint;
+ int64_t nTransactionsLastCheckpoint;
+ double fTransactionsPerDay;
+};
+
// Returns true if block passes checkpoint checks
bool CheckBlock(int nHeight, const uint256& hash);
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 129d184868..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,36 +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 ((!Params().SkipProofOfWorkCheck()) &&
(block.nBits != GetNextWorkRequired(pindexPrev, &block)))
- return state.DoS(100, error("AcceptBlock() : incorrect proof of work"),
+ 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");
}
}
@@ -2392,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;
@@ -2719,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;
}
@@ -2733,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;
}
@@ -2892,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;
@@ -3143,7 +3137,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
}
}
} 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/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 5e2fdc6c30..9872ebc1f6 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -12,6 +12,7 @@
#include "guiconstants.h"
#include "guiutil.h"
#include "intro.h"
+#include "networkstyle.h"
#include "optionsmodel.h"
#include "splashscreen.h"
#include "utilitydialog.h"
@@ -190,9 +191,9 @@ public:
/// Create options model
void createOptionsModel();
/// Create main window
- void createWindow(bool isaTestNet);
+ void createWindow(const NetworkStyle *networkStyle);
/// Create splash screen
- void createSplashScreen(bool isaTestNet);
+ void createSplashScreen(const NetworkStyle *networkStyle);
/// Request core initialization
void requestInitialize();
@@ -331,18 +332,18 @@ void BitcoinApplication::createOptionsModel()
optionsModel = new OptionsModel();
}
-void BitcoinApplication::createWindow(bool isaTestNet)
+void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
{
- window = new BitcoinGUI(isaTestNet, 0);
+ window = new BitcoinGUI(networkStyle, 0);
pollShutdownTimer = new QTimer(window);
connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown()));
pollShutdownTimer->start(200);
}
-void BitcoinApplication::createSplashScreen(bool isaTestNet)
+void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
{
- SplashScreen *splash = new SplashScreen(0, isaTestNet);
+ SplashScreen *splash = new SplashScreen(0, networkStyle);
// We don't hold a direct pointer to the splash screen after creation, so use
// Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually.
splash->setAttribute(Qt::WA_DeleteOnClose);
@@ -572,12 +573,10 @@ int main(int argc, char *argv[])
if (!PaymentServer::ipcParseCommandLine(argc, argv))
exit(0);
#endif
- bool isaTestNet = Params().NetworkID() != CBaseChainParams::MAIN;
+ QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString())));
+ assert(!networkStyle.isNull());
// Allow for separate UI settings for testnets
- if (isaTestNet)
- QApplication::setApplicationName(QAPP_APP_NAME_TESTNET);
- else
- QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT);
+ QApplication::setApplicationName(networkStyle->getAppName());
// Re-initialize translations after changing application name (language in network-specific settings can be different)
initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
@@ -617,11 +616,11 @@ int main(int argc, char *argv[])
uiInterface.InitMessage.connect(InitMessage);
if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false))
- app.createSplashScreen(isaTestNet);
+ app.createSplashScreen(networkStyle.data());
try
{
- app.createWindow(isaTestNet);
+ app.createWindow(networkStyle.data());
app.requestInitialize();
#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("Bitcoin Core didn't yet exit safely..."), (HWND)app.getMainWinId());
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 7380fbd240..8a945606dc 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -8,6 +8,7 @@
#include "clientmodel.h"
#include "guiconstants.h"
#include "guiutil.h"
+#include "networkstyle.h"
#include "notificator.h"
#include "openuridialog.h"
#include "optionsdialog.h"
@@ -59,7 +60,7 @@
const QString BitcoinGUI::DEFAULT_WALLET = "~Default";
-BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
+BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
QMainWindow(parent),
clientModel(0),
walletFrame(0),
@@ -112,26 +113,13 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
} else {
windowTitle += tr("Node");
}
-
- if (!fIsTestnet)
- {
+ windowTitle += " " + networkStyle->getTitleAddText();
#ifndef Q_OS_MAC
- QApplication::setWindowIcon(QIcon(":icons/bitcoin"));
- setWindowIcon(QIcon(":icons/bitcoin"));
+ QApplication::setWindowIcon(networkStyle->getAppIcon());
+ setWindowIcon(networkStyle->getAppIcon());
#else
- MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin"));
+ MacDockIconHandler::instance()->setIcon(networkStyle->getAppIcon());
#endif
- }
- else
- {
- windowTitle += " " + tr("[testnet]");
-#ifndef Q_OS_MAC
- QApplication::setWindowIcon(QIcon(":icons/bitcoin_testnet"));
- setWindowIcon(QIcon(":icons/bitcoin_testnet"));
-#else
- MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
-#endif
- }
setWindowTitle(windowTitle);
#if defined(Q_OS_MAC) && QT_VERSION < 0x050000
@@ -161,7 +149,7 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
// Create actions for the toolbar, menu bar and tray/dock icon
// Needs walletFrame to be initialized
- createActions(fIsTestnet);
+ createActions(networkStyle);
// Create application menu bar
createMenuBar();
@@ -170,7 +158,7 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
createToolBars();
// Create system tray icon and notification
- createTrayIcon(fIsTestnet);
+ createTrayIcon(networkStyle);
// Create status bar
statusBar();
@@ -248,7 +236,7 @@ BitcoinGUI::~BitcoinGUI()
#endif
}
-void BitcoinGUI::createActions(bool fIsTestnet)
+void BitcoinGUI::createActions(const NetworkStyle *networkStyle)
{
QActionGroup *tabGroup = new QActionGroup(this);
@@ -295,10 +283,7 @@ void BitcoinGUI::createActions(bool fIsTestnet)
quitAction->setStatusTip(tr("Quit application"));
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
quitAction->setMenuRole(QAction::QuitRole);
- if (!fIsTestnet)
- aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About Bitcoin Core"), this);
- else
- aboutAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&About Bitcoin Core"), this);
+ aboutAction = new QAction(networkStyle->getAppIcon(), tr("&About Bitcoin Core"), this);
aboutAction->setStatusTip(tr("Show information about Bitcoin Core"));
aboutAction->setMenuRole(QAction::AboutRole);
#if QT_VERSION < 0x050000
@@ -311,10 +296,7 @@ void BitcoinGUI::createActions(bool fIsTestnet)
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin"));
optionsAction->setMenuRole(QAction::PreferencesRole);
- if (!fIsTestnet)
- toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this);
- else
- toggleHideAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&Show / Hide"), this);
+ toggleHideAction = new QAction(networkStyle->getAppIcon(), tr("&Show / Hide"), this);
toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
@@ -505,22 +487,13 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled)
openAction->setEnabled(enabled);
}
-void BitcoinGUI::createTrayIcon(bool fIsTestnet)
+void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
{
#ifndef Q_OS_MAC
trayIcon = new QSystemTrayIcon(this);
-
- if (!fIsTestnet)
- {
- trayIcon->setToolTip(tr("Bitcoin Core client"));
- trayIcon->setIcon(QIcon(":/icons/bitcoin"));
- }
- else
- {
- trayIcon->setToolTip(tr("Bitcoin Core client") + " " + tr("[testnet]"));
- trayIcon->setIcon(QIcon(":/icons/bitcoin_testnet"));
- }
-
+ QString toolTip = tr("Bitcoin Core client") + " " + networkStyle->getTitleAddText();
+ trayIcon->setToolTip(toolTip);
+ trayIcon->setIcon(networkStyle->getAppIcon());
trayIcon->show();
#endif
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 8af6eda867..f65f0e9137 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -19,6 +19,7 @@
#include <QSystemTrayIcon>
class ClientModel;
+class NetworkStyle;
class Notificator;
class OptionsModel;
class RPCConsole;
@@ -46,7 +47,7 @@ class BitcoinGUI : public QMainWindow
public:
static const QString DEFAULT_WALLET;
- explicit BitcoinGUI(bool fIsTestnet = false, QWidget *parent = 0);
+ explicit BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent = 0);
~BitcoinGUI();
/** Set the client model.
@@ -114,13 +115,13 @@ private:
int spinnerFrame;
/** Create the main UI actions. */
- void createActions(bool fIsTestnet);
+ void createActions(const NetworkStyle *networkStyle);
/** Create the menu bar and sub-menus. */
void createMenuBar();
/** Create the toolbars */
void createToolBars();
/** Create system tray icon and notification */
- void createTrayIcon(bool fIsTestnet);
+ void createTrayIcon(const NetworkStyle *networkStyle);
/** Create system tray menu (or setup the dock menu) */
void createTrayIconMenu();
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/networkstyle.cpp b/src/qt/networkstyle.cpp
new file mode 100644
index 0000000000..62c44703f4
--- /dev/null
+++ b/src/qt/networkstyle.cpp
@@ -0,0 +1,47 @@
+// Copyright (c) 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 "networkstyle.h"
+
+#include "guiconstants.h"
+
+#include <QApplication>
+
+static const struct {
+ const char *networkId;
+ const char *appName;
+ const char *appIcon;
+ const char *titleAddText;
+ const char *splashImage;
+} network_styles[] = {
+ {"main", QAPP_APP_NAME_DEFAULT, ":/icons/bitcoin", "", ":/images/splash"},
+ {"test", QAPP_APP_NAME_TESTNET, ":/icons/bitcoin_testnet", QT_TRANSLATE_NOOP("SplashScreen", "[testnet]"), ":/images/splash_testnet"},
+ {"regtest", QAPP_APP_NAME_TESTNET, ":/icons/bitcoin_testnet", "[regtest]", ":/images/splash_testnet"}
+};
+static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles);
+
+// titleAddText needs to be const char* for tr()
+NetworkStyle::NetworkStyle(const QString &appName, const QString &appIcon, const char *titleAddText, const QString &splashImage):
+ appName(appName),
+ appIcon(appIcon),
+ titleAddText(qApp->translate("SplashScreen", titleAddText)),
+ splashImage(splashImage)
+{
+}
+
+const NetworkStyle *NetworkStyle::instantiate(const QString &networkId)
+{
+ for (unsigned x=0; x<network_styles_count; ++x)
+ {
+ if (networkId == network_styles[x].networkId)
+ {
+ return new NetworkStyle(
+ network_styles[x].appName,
+ network_styles[x].appIcon,
+ network_styles[x].titleAddText,
+ network_styles[x].splashImage);
+ }
+ }
+ return 0;
+}
diff --git a/src/qt/networkstyle.h b/src/qt/networkstyle.h
new file mode 100644
index 0000000000..99304d61a3
--- /dev/null
+++ b/src/qt/networkstyle.h
@@ -0,0 +1,33 @@
+// Copyright (c) 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_NETWORKSTYLE
+#define H_NETWORKSTYLE
+
+#include <QIcon>
+#include <QPixmap>
+#include <QString>
+
+/* Coin network-specific GUI style information */
+class NetworkStyle
+{
+public:
+ /** Get style associated with provided BIP70 network id, or 0 if not known */
+ static const NetworkStyle *instantiate(const QString &networkId);
+
+ const QString &getAppName() const { return appName; }
+ const QIcon &getAppIcon() const { return appIcon; }
+ const QString &getTitleAddText() const { return titleAddText; }
+ const QPixmap &getSplashImage() const { return splashImage; }
+
+private:
+ NetworkStyle(const QString &appName, const QString &appIcon, const char *titleAddText, const QString &splashImage);
+
+ QString appName;
+ QIcon appIcon;
+ QString titleAddText;
+ QPixmap splashImage;
+};
+
+#endif // H_NETWORKSTYLE
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/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 4fe610794f..b4b81440ca 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -6,6 +6,7 @@
#include "clientversion.h"
#include "init.h"
+#include "networkstyle.h"
#include "ui_interface.h"
#include "util.h"
#include "version.h"
@@ -19,7 +20,7 @@
#include <QDesktopWidget>
#include <QPainter>
-SplashScreen::SplashScreen(Qt::WindowFlags f, bool isTestNet) :
+SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) :
QWidget(0, f), curAlignment(0)
{
// set reference point, paddings
@@ -34,17 +35,12 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, bool isTestNet) :
QString titleText = tr("Bitcoin Core");
QString versionText = QString("Version %1").arg(QString::fromStdString(FormatFullVersion()));
QString copyrightText = QChar(0xA9)+QString(" 2009-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Bitcoin Core developers"));
- QString testnetAddText = QString(tr("[testnet]")); // define text to place as single text object
+ QString titleAddText = networkStyle->getTitleAddText();
QString font = "Arial";
// load the bitmap for writing some text over it
- if(isTestNet) {
- pixmap = QPixmap(":/images/splash_testnet");
- }
- else {
- pixmap = QPixmap(":/images/splash");
- }
+ pixmap = networkStyle->getSplashImage();
QPainter pixPaint(&pixmap);
pixPaint.setPen(QColor(100,100,100));
@@ -78,23 +74,20 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, bool isTestNet) :
pixPaint.setFont(QFont(font, 10*fontFactor));
pixPaint.drawText(pixmap.width()-titleTextWidth-paddingRight,paddingTop+titleCopyrightVSpace,copyrightText);
- // draw testnet string if testnet is on
- if(isTestNet) {
+ // draw additional text if special network
+ if(!titleAddText.isEmpty()) {
QFont boldFont = QFont(font, 10*fontFactor);
boldFont.setWeight(QFont::Bold);
pixPaint.setFont(boldFont);
fm = pixPaint.fontMetrics();
- int testnetAddTextWidth = fm.width(testnetAddText);
- pixPaint.drawText(pixmap.width()-testnetAddTextWidth-10,15,testnetAddText);
+ int titleAddTextWidth = fm.width(titleAddText);
+ pixPaint.drawText(pixmap.width()-titleAddTextWidth-10,15,titleAddText);
}
pixPaint.end();
// Set window title
- if(isTestNet)
- setWindowTitle(titleText + " " + testnetAddText);
- else
- setWindowTitle(titleText);
+ setWindowTitle(titleText + " " + titleAddText);
// Resize window and move to center of desktop, disallow resizing
QRect r(QPoint(), pixmap.size());
@@ -177,5 +170,6 @@ void SplashScreen::paintEvent(QPaintEvent *event)
void SplashScreen::closeEvent(QCloseEvent *event)
{
+ StartShutdown(); // allows an "emergency" shutdown during startup
event->ignore();
}
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index 89c21e6457..128edadbee 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -7,6 +7,8 @@
#include <QSplashScreen>
+class NetworkStyle;
+
/** Class for the splashscreen with information of the running client.
*
* @note this is intentionally not a QSplashScreen. Bitcoin Core initialization
@@ -18,7 +20,7 @@ class SplashScreen : public QWidget
Q_OBJECT
public:
- explicit SplashScreen(Qt::WindowFlags f, bool isTestNet);
+ explicit SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle);
~SplashScreen();
protected:
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/rpcmining.cpp b/src/rpcmining.cpp
index e794bf69e0..c767835a27 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -239,7 +239,7 @@ Value getmininginfo(const Array& params, bool fHelp)
obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
obj.push_back(Pair("networkhashps", getnetworkhashps(params, false)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
- obj.push_back(Pair("testnet", Params().NetworkID() == CBaseChainParams::TESTNET));
+ obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
obj.push_back(Pair("chain", Params().NetworkIDString()));
#ifdef ENABLE_WALLET
obj.push_back(Pair("generate", getgenerate(params, false)));
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index dd45eefd58..8be14b567c 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -87,7 +87,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("testnet", Params().NetworkID() == CBaseChainParams::TESTNET));
+ obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
#ifdef ENABLE_WALLET
if (pwalletMain) {
obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
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/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/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/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/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 48a5635d8f..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);
@@ -89,7 +92,7 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMu
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);
}
@@ -525,15 +588,15 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
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)
@@ -553,46 +616,46 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
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)
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 6e5f0e3fac..afd63d2717 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -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/wallet.cpp b/src/wallet.cpp
index 1653084495..19e43f6ec2 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>
@@ -447,17 +449,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
@@ -465,8 +475,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;
@@ -1089,7 +1103,7 @@ CAmount CWallet::GetWatchOnlyBalance() const
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
}
-
+
return nTotal;
}
diff --git a/src/wallet.h b/src/wallet.h
index 1ccc29d3c8..fa8a94dfc1 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 a851db65cd..783f766f6f 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;
@@ -924,7 +924,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
@@ -965,7 +965,6 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys)
}
ptxn->commit(0);
pdbCopy->close(0);
- delete pdbCopy;
return fSuccess;
}