diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2014-11-20 13:12:45 +0100 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2014-11-20 13:19:47 +0100 |
commit | 9842ed465b44c8eaa8b307c18449dd9d8e04f217 (patch) | |
tree | f51866e12e89d6176294dc48c4c4ea3da39b714b | |
parent | b5d1b1092998bc95313856d535c632ea5a8f9104 (diff) | |
parent | 9eb5a5fbef5270fda10c15c60a297b4cd19b681e (diff) |
Merge pull request #5235
9eb5a5f build: pad header for osx libs (Cory Fields)
9ed8979 build: fix static dll link for mingw (Cory Fields)
19df238 build: shared lib build should work reasonably well now (Cory Fields)
269efa3 build: add quick consensus lib tests (Cory Fields)
cdd36c6 build: add --with-libs so that libs are optional (Cory Fields)
2cf5f16 build: add libbitcoinconsensus files and hook up the lib build (Cory Fields)
ee64c53 build: remove internal/protected build attribute checks (Cory Fields)
f36a40f build: check visibility attributes (Cory Fields)
811a765 build: mingw needs libssp for hardening with dlls (Cory Fields)
e0077de build: make a distinction between static app ldflags and static lib ldflags (Cory Fields)
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | build-aux/m4/ax_gcc_func_attribute.m4 | 217 | ||||
-rw-r--r-- | configure.ac | 46 | ||||
-rw-r--r-- | src/Makefile.am | 43 | ||||
-rw-r--r-- | src/Makefile.qt.include | 2 | ||||
-rw-r--r-- | src/Makefile.qttest.include | 2 | ||||
-rw-r--r-- | src/Makefile.test.include | 4 | ||||
-rw-r--r-- | src/script/bitcoinconsensus.cpp | 91 | ||||
-rw-r--r-- | src/script/bitcoinconsensus.h | 67 | ||||
-rw-r--r-- | src/test/script_tests.cpp | 13 |
10 files changed, 474 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore index c97432df92..7343e722d5 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ src/qt/test/moc*.cpp .deps .dirstamp +.libs .*.swp *.*~* *.bak @@ -66,6 +67,10 @@ src/qt/test/moc*.cpp *.json.h *.raw.h +#libtool object files +*.lo +*.la + # Compilation and Qt preprocessor part *.qm Makefile diff --git a/build-aux/m4/ax_gcc_func_attribute.m4 b/build-aux/m4/ax_gcc_func_attribute.m4 new file mode 100644 index 0000000000..275ca63a2c --- /dev/null +++ b/build-aux/m4/ax_gcc_func_attribute.m4 @@ -0,0 +1,217 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_gcc_func_attribute.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_FUNC_ATTRIBUTE(ATTRIBUTE) +# +# DESCRIPTION +# +# This macro checks if the compiler supports one of GCC's function +# attributes; many other compilers also provide function attributes with +# the same syntax. Compiler warnings are used to detect supported +# attributes as unsupported ones are ignored by default so quieting +# warnings when using this macro will yield false positives. +# +# The ATTRIBUTE parameter holds the name of the attribute to be checked. +# +# If ATTRIBUTE is supported define HAVE_FUNC_ATTRIBUTE_<ATTRIBUTE>. +# +# The macro caches its result in the ax_cv_have_func_attribute_<attribute> +# variable. +# +# The macro currently supports the following function attributes: +# +# alias +# aligned +# alloc_size +# always_inline +# artificial +# cold +# const +# constructor +# deprecated +# destructor +# dllexport +# dllimport +# error +# externally_visible +# flatten +# format +# format_arg +# gnu_inline +# hot +# ifunc +# leaf +# malloc +# noclone +# noinline +# nonnull +# noreturn +# nothrow +# optimize +# pure +# unused +# used +# visibility +# warning +# warn_unused_result +# weak +# weakref +# +# Unsuppored function attributes will be tested with a prototype returning +# an int and not accepting any arguments and the result of the check might +# be wrong or meaningless so use with care. +# +# LICENSE +# +# Copyright (c) 2013 Gabriele Svelto <gabriele.svelto@gmail.com> +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 2 + +AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ + AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1]) + + AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([ + m4_case([$1], + [alias], [ + int foo( void ) { return 0; } + int bar( void ) __attribute__(($1("foo"))); + ], + [aligned], [ + int foo( void ) __attribute__(($1(32))); + ], + [alloc_size], [ + void *foo(int a) __attribute__(($1(1))); + ], + [always_inline], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [artificial], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [cold], [ + int foo( void ) __attribute__(($1)); + ], + [const], [ + int foo( void ) __attribute__(($1)); + ], + [constructor], [ + int foo( void ) __attribute__(($1)); + ], + [deprecated], [ + int foo( void ) __attribute__(($1(""))); + ], + [destructor], [ + int foo( void ) __attribute__(($1)); + ], + [dllexport], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [dllimport], [ + int foo( void ) __attribute__(($1)); + ], + [error], [ + int foo( void ) __attribute__(($1(""))); + ], + [externally_visible], [ + int foo( void ) __attribute__(($1)); + ], + [flatten], [ + int foo( void ) __attribute__(($1)); + ], + [format], [ + int foo(const char *p, ...) __attribute__(($1(printf, 1, 2))); + ], + [format_arg], [ + char *foo(const char *p) __attribute__(($1(1))); + ], + [gnu_inline], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [hot], [ + int foo( void ) __attribute__(($1)); + ], + [ifunc], [ + int my_foo( void ) { return 0; } + static int (*resolve_foo(void))(void) { return my_foo; } + int foo( void ) __attribute__(($1("resolve_foo"))); + ], + [leaf], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [malloc], [ + void *foo( void ) __attribute__(($1)); + ], + [noclone], [ + int foo( void ) __attribute__(($1)); + ], + [noinline], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [nonnull], [ + int foo(char *p) __attribute__(($1(1))); + ], + [noreturn], [ + void foo( void ) __attribute__(($1)); + ], + [nothrow], [ + int foo( void ) __attribute__(($1)); + ], + [optimize], [ + __attribute__(($1(3))) int foo( void ) { return 0; } + ], + [pure], [ + int foo( void ) __attribute__(($1)); + ], + [unused], [ + int foo( void ) __attribute__(($1)); + ], + [used], [ + int foo( void ) __attribute__(($1)); + ], + [visibility], [ + int foo_def( void ) __attribute__(($1("default"))); + int foo_hid( void ) __attribute__(($1("hidden"))); + ], + [warning], [ + int foo( void ) __attribute__(($1(""))); + ], + [warn_unused_result], [ + int foo( void ) __attribute__(($1)); + ], + [weak], [ + int foo( void ) __attribute__(($1)); + ], + [weakref], [ + static int foo( void ) { return 0; } + static int bar( void ) __attribute__(($1("foo"))); + ], + [ + m4_warn([syntax], [Unsupported attribute $1, the test may fail]) + int foo( void ) __attribute__(($1)); + ] + )], []) + ], + dnl GCC doesn't exit with an error if an unknown attribute is + dnl provided but only outputs a warning, so accept the attribute + dnl only if no warning were issued. + [AS_IF([test -s conftest.err], + [AS_VAR_SET([ac_var], [no])], + [AS_VAR_SET([ac_var], [yes])])], + [AS_VAR_SET([ac_var], [no])]) + ]) + + AS_IF([test yes = AS_VAR_GET([ac_var])], + [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_FUNC_ATTRIBUTE_$1), 1, + [Define to 1 if the system has the `$1' function attribute])], []) + + AS_VAR_POPDEF([ac_var]) +]) diff --git a/configure.ac b/configure.ac index c0489f5be7..6784521d81 100644 --- a/configure.ac +++ b/configure.ac @@ -49,7 +49,7 @@ case $host in ;; esac dnl Libtool init checks. -LT_INIT([disable-shared]) +LT_INIT([pic-only]) dnl Check/return PATH for base programs. AC_PATH_TOOL(AR, ar) @@ -201,12 +201,9 @@ case $host in AC_CHECK_LIB([iphlpapi], [main],, AC_MSG_ERROR(lib missing)) AC_CHECK_LIB([crypt32], [main],, AC_MSG_ERROR(lib missing)) - AX_CHECK_LINK_FLAG([[-static-libgcc]],[LDFLAGS="$LDFLAGS -static-libgcc"]) - AX_CHECK_LINK_FLAG([[-static-libstdc++]],[LDFLAGS="$LDFLAGS -static-libstdc++"]) - # -static is interpreted by libtool, where it has a different meaning. # In libtool-speak, it's -all-static. - AX_CHECK_LINK_FLAG([[-static]],[LDFLAGS="$LDFLAGS -static"; LIBTOOL_LDFLAGS="$LIBTOOL_LDFLAGS -all-static"]) + AX_CHECK_LINK_FLAG([[-static]],[LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static"]) AC_PATH_PROG([MAKENSIS], [makensis], none) if test x$MAKENSIS = xnone; then @@ -229,6 +226,15 @@ case $host in *) AC_MSG_ERROR("Could not determine win32/win64 for installer") ;; esac AC_SUBST(WINDOWS_BITS) + + dnl libtool insists upon adding -nostdlib and a list of objects/libs to link against. + dnl That breaks our ability to build dll's with static libgcc/libstdc++/libssp. Override + dnl its command here, with the predeps/postdeps removed, and -static inserted. Postdeps are + dnl also overridden to prevent their insertion later. + dnl This should only affect dll's. + archive_cmds_CXX="\$CC -shared \$libobjs \$deplibs \$compiler_flags -static -o \$output_objdir/\$soname \${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker \$lib" + postdeps_CXX= + ;; *darwin*) TARGET_OS=darwin @@ -279,6 +285,7 @@ case $host in esac fi + AX_CHECK_LINK_FLAG([[-Wl,-headerpad_max_install_names]], [LDFLAGS="$LDFLAGS -Wl,-headerpad_max_install_names"]) CPPFLAGS="$CPPFLAGS -DMAC_OSX" ;; *linux*) @@ -349,6 +356,10 @@ fi AX_CHECK_LINK_FLAG([[-Wl,--large-address-aware]], [LDFLAGS="$LDFLAGS -Wl,--large-address-aware"]) +AX_GCC_FUNC_ATTRIBUTE([visibility]) +AX_GCC_FUNC_ATTRIBUTE([dllexport]) +AX_GCC_FUNC_ATTRIBUTE([dllimport]) + if test x$use_glibc_compat != xno; then #__fdelt_chk's params and return type have changed from long unsigned int to long int. @@ -389,6 +400,12 @@ if test x$use_hardening != xno; then AX_CHECK_LINK_FLAG([[-pie]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"]) fi + case $host in + *mingw*) + AC_CHECK_LIB([ssp], [main],, AC_MSG_ERROR(lib missing)) + ;; + esac + CXXFLAGS="$CXXFLAGS $HARDENED_CXXFLAGS" CPPFLAGS="$CPPFLAGS $HARDENED_CPPFLAGS" LDFLAGS="$LDFLAGS $HARDENED_LDFLAGS" @@ -603,6 +620,12 @@ AC_ARG_WITH([utils], [build_bitcoin_utils=$withval], [build_bitcoin_utils=yes]) +AC_ARG_WITH([libs], + [AS_HELP_STRING([--with-libs], + [build libraries (default=yes)])], + [build_bitcoin_libs=$withval], + [build_bitcoin_libs=yes]) + AC_ARG_WITH([daemon], [AS_HELP_STRING([--with-daemon], [build bitcoind daemon (default=yes)])], @@ -653,6 +676,13 @@ AC_MSG_CHECKING([whether to build utils (bitcoin-cli bitcoin-tx)]) AM_CONDITIONAL([BUILD_BITCOIN_UTILS], [test x$build_bitcoin_utils = xyes]) AC_MSG_RESULT($build_bitcoin_utils) +AC_MSG_CHECKING([whether to build libraries]) +AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test x$build_bitcoin_libs = xyes]) +if test x$build_bitcoin_libs = xyes; then + AC_DEFINE(HAVE_CONSENSUS_LIB, 1, [Define this symbol if the consensus lib has been built]) +fi +AC_MSG_RESULT($build_bitcoin_libs) + dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus BITCOIN_QT_CONFIGURE([$use_pkgconfig], [qt4]) @@ -769,8 +799,8 @@ else AC_MSG_RESULT([no]) fi -if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests = xnononono; then - AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-daemon --with-gui or --enable-tests]) +if test x$build_bitcoin_utils$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_tests = xnononono; then + AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui or --enable-tests]) fi AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) @@ -801,7 +831,7 @@ AC_SUBST(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE) AC_SUBST(COPYRIGHT_YEAR, _COPYRIGHT_YEAR) AC_SUBST(RELDFLAGS) -AC_SUBST(LIBTOOL_LDFLAGS) +AC_SUBST(LIBTOOL_APP_LDFLAGS) AC_SUBST(USE_UPNP) AC_SUBST(USE_QRCODE) AC_SUBST(BOOST_LIBS) diff --git a/src/Makefile.am b/src/Makefile.am index 556fd49c0b..0d45203c90 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -49,6 +49,13 @@ BITCOIN_INCLUDES += $(BDB_CPPFLAGS) noinst_LIBRARIES += libbitcoin_wallet.a endif +if BUILD_BITCOIN_LIBS +lib_LTLIBRARIES = libbitcoinconsensus.la +LIBBITCOIN_CONSENSUS=libbitcoinconsensus.la +else +LIBBITCOIN_CONSENSUS= +endif + bin_PROGRAMS = TESTS = @@ -295,7 +302,7 @@ endif bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES) -bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) +bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) # bitcoin-cli binary # bitcoin_cli_LDADD = \ @@ -324,12 +331,42 @@ bitcoin_tx_LDADD = \ bitcoin_tx_SOURCES = bitcoin-tx.cpp bitcoin_tx_CPPFLAGS = $(BITCOIN_INCLUDES) # -bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) +bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS bitcoin_cli_SOURCES += bitcoin-cli-res.rc endif -bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) +bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) + +if BUILD_BITCOIN_LIBS +include_HEADERS = script/bitcoinconsensus.h +libbitcoinconsensus_la_SOURCES = \ + core/transaction.cpp \ + crypto/sha1.cpp \ + crypto/sha2.cpp \ + crypto/ripemd160.cpp \ + eccryptoverify.cpp \ + ecwrapper.cpp \ + hash.cpp \ + pubkey.cpp \ + script/script.cpp \ + script/interpreter.cpp \ + script/bitcoinconsensus.cpp \ + uint256.cpp \ + utilstrencodings.cpp + +if GLIBC_BACK_COMPAT + libbitcoinconsensus_la_SOURCES += compat/glibc_compat.cpp + libbitcoinconsensus_la_SOURCES += compat/glibcxx_compat.cpp +endif + +libbitcoinconsensus_la_LDFLAGS = -no-undefined $(RELDFLAGS) +libbitcoinconsensus_la_LIBADD = $(CRYPTO_LIBS) +libbitcoinconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCOIN_INTERNAL +if USE_LIBSECP256K1 +libbitcoinconsensus_la_LIBADD += secp256k1/libsecp256k1.la +endif +endif CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index fac214bdca..898337ad6f 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -361,7 +361,7 @@ qt_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET) endif qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) -qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) +qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) qt_bitcoin_qt_LIBTOOLFLAGS = --tag CXX #locale/foo.ts -> locale/foo.qm diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 622411ca68..c5392cf307 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -33,7 +33,7 @@ endif qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \ $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) -qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) +qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 79509c9a3e..5fd2afe50d 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -85,8 +85,8 @@ if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) endif -test_test_bitcoin_LDADD += $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) -test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) +test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) +test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static-libtool-libs nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp new file mode 100644 index 0000000000..4faa760ad7 --- /dev/null +++ b/src/script/bitcoinconsensus.cpp @@ -0,0 +1,91 @@ +// 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 "bitcoinconsensus.h" + +#include "core/transaction.h" +#include "script/interpreter.h" +#include "version.h" + +namespace { + +/** A class that deserializes a single CTransaction one time. */ +class TxInputStream +{ +public: + TxInputStream(int nTypeIn, int nVersionIn, const unsigned char *txTo, size_t txToLen) : + m_type(nTypeIn), + m_version(nVersionIn), + m_data(txTo), + m_remaining(txToLen) + {} + + TxInputStream& read(char* pch, size_t nSize) + { + if (nSize > m_remaining) + throw std::ios_base::failure(std::string(__func__) + ": end of data"); + + if (pch == NULL) + throw std::ios_base::failure(std::string(__func__) + ": bad destination buffer"); + + if (m_data == NULL) + throw std::ios_base::failure(std::string(__func__) + ": bad source buffer"); + + memcpy(pch, m_data, nSize); + m_remaining -= nSize; + m_data += nSize; + return *this; + } + + template<typename T> + TxInputStream& operator>>(T& obj) + { + ::Unserialize(*this, obj, m_type, m_version); + return *this; + } + +private: + const int m_type; + const int m_version; + const unsigned char* m_data; + size_t m_remaining; +}; + +inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror) +{ + if (ret) + *ret = serror; + return 0; +} + +} // anon namespace + +int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, + const unsigned char *txTo , unsigned int txToLen, + unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err) +{ + try { + TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen); + CTransaction tx; + stream >> tx; + if (nIn >= tx.vin.size()) + return set_error(err, bitcoinconsensus_ERR_TX_INDEX); + if (tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) != txToLen) + return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH); + + // Regardless of the verification result, the tx did not error. + set_error(err, bitcoinconsensus_ERR_OK); + + return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, SignatureChecker(tx, nIn), NULL); + } catch (std::exception &e) { + return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing + } +} + +unsigned int bitcoinconsensus_version() +{ + // Just use the API version for now + return BITCOINCONSENSUS_API_VER; +} diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h new file mode 100644 index 0000000000..15e3337a8d --- /dev/null +++ b/src/script/bitcoinconsensus.h @@ -0,0 +1,67 @@ +// 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 BITCOIN_BITCOINCONSENSUS_H +#define BITCOIN_BITCOINCONSENSUS_H + +#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" + #if defined(_WIN32) + #if defined(DLL_EXPORT) + #if defined(HAVE_FUNC_ATTRIBUTE_DLLEXPORT) + #define EXPORT_SYMBOL __declspec(dllexport) + #else + #define EXPORT_SYMBOL + #endif + #endif + #elif defined(HAVE_FUNC_ATTRIBUTE_VISIBILITY) + #define EXPORT_SYMBOL __attribute__ ((visibility ("default"))) + #endif +#elif defined(MSC_VER) && !defined(STATIC_LIBBITCOINCONSENSUS) + #define EXPORT_SYMBOL __declspec(dllimport) +#endif + +#ifndef EXPORT_SYMBOL + #define EXPORT_SYMBOL +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define BITCOINCONSENSUS_API_VER 0 + +typedef enum bitcoinconsensus_error_t +{ + bitcoinconsensus_ERR_OK = 0, + bitcoinconsensus_ERR_TX_INDEX, + bitcoinconsensus_ERR_TX_SIZE_MISMATCH, + bitcoinconsensus_ERR_TX_DESERIALIZE, +} bitcoinconsensus_error; + +/** Script verification flags */ +enum +{ + bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0, + bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts +}; + +/// Returns 1 if the input nIn of the serialized transaction pointed to by +/// txTo correctly spends the scriptPubKey pointed to by scriptPubKey under +/// the additional constraints specified by flags. +/// If not NULL, err will contain an error/success code for the operation +EXPORT_SYMBOL int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, + const unsigned char *txTo , unsigned int txToLen, + unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err); + +EXPORT_SYMBOL unsigned int bitcoinconsensus_version(); + +#ifdef __cplusplus +} // extern "C" +#endif + +#undef EXPORT_SYMBOL + +#endif // BITCOIN_BITCOINCONSENSUS_H diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index d98154571b..36aaa6903f 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -14,6 +14,10 @@ #include "script/sign.h" #include "util.h" +#if defined(HAVE_CONSENSUS_LIB) +#include "script/bitcoinconsensus.h" +#endif + #include <fstream> #include <stdint.h> #include <string> @@ -94,8 +98,15 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMu void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message) { ScriptError err; - BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, SignatureChecker(BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)), 0), &err) == expect, message); + CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)); + CMutableTransaction tx2 = tx; + BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, SignatureChecker(tx, 0), &err) == expect, message); BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message); +#if defined(HAVE_CONSENSUS_LIB) + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << tx2; + BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(begin_ptr(scriptPubKey), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect,message); +#endif } void static NegateSignatureS(std::vector<unsigned char>& vchSig) { |