diff --git a/.gitignore b/.gitignore index f7bcbd1459..367942103f 100644 --- a/.gitignore +++ b/.gitignore @@ -136,6 +136,7 @@ test/lint/test_runner/target/ /doc/doxygen/ +libbitcoinconsensus.pc contrib/devtools/split-debug.sh # Output from running db4 installation diff --git a/Makefile.am b/Makefile.am index b746299a42..73f1f6c4ea 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,6 +14,11 @@ endif .PHONY: deploy FORCE .INTERMEDIATE: $(COVERAGE_INFO) +if BUILD_BITCOIN_LIBS +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libbitcoinconsensus.pc +endif + BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT) BITCOIN_QT_BIN=$(top_builddir)/src/qt/$(BITCOIN_GUI_NAME)$(EXEEXT) BITCOIN_TEST_BIN=$(top_builddir)/src/test/$(BITCOIN_TEST_NAME)$(EXEEXT) diff --git a/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj b/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj index a34ef41d16..95fdcdb79b 100644 --- a/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj +++ b/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj @@ -15,6 +15,7 @@ + diff --git a/ci/test/00_setup_env_native_previous_releases.sh b/ci/test/00_setup_env_native_previous_releases.sh index 9da3b18999..3166686d9a 100755 --- a/ci/test/00_setup_env_native_previous_releases.sh +++ b/ci/test/00_setup_env_native_previous_releases.sh @@ -16,5 +16,5 @@ export RUN_UNIT_TESTS_SEQUENTIAL="true" export RUN_UNIT_TESTS="false" export GOAL="install" export DOWNLOAD_PREVIOUS_RELEASES="true" -export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports --enable-debug \ +export BITCOIN_CONFIG="--enable-zmq --with-libs=no --with-gui=qt5 --enable-reduce-exports --enable-debug \ CFLAGS=\"-g0 -O2 -funsigned-char\" CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE' CXXFLAGS=\"-g0 -O2 -funsigned-char\"" diff --git a/configure.ac b/configure.ac index d26d71f6cc..813958bff6 100644 --- a/configure.ac +++ b/configure.ac @@ -602,6 +602,12 @@ AC_ARG_ENABLE([util-util], build_bitcoin_chainstate=no build_experimental_kernel_lib=no +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)])], @@ -1194,6 +1200,7 @@ if test "$enable_fuzz" = "yes"; then build_bitcoin_chainstate=no build_bitcoin_wallet=no build_bitcoind=no + build_bitcoin_libs=no bitcoin_enable_qt=no bitcoin_enable_qt_test=no bitcoin_enable_qt_dbus=no @@ -1378,7 +1385,7 @@ if test "$use_boost" = "yes"; then dnl Check for Boost headers AX_BOOST_BASE([1.73.0],[],[AC_MSG_ERROR([Boost is not available!])]) if test "$want_boost" = "no"; then - AC_MSG_ERROR([Boost is required]) + AC_MSG_ERROR([only libbitcoinconsensus can be built without Boost]) fi dnl we don't use multi_index serialization @@ -1554,8 +1561,18 @@ fi AM_CONDITIONAL([BUILD_BITCOIN_CHAINSTATE], [test $build_bitcoin_chainstate = "yes"]) AC_MSG_RESULT($build_bitcoin_chainstate) +AC_MSG_CHECKING([whether to build libraries]) +AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test $build_bitcoin_libs = "yes"]) + +if test "$build_bitcoin_libs" = "yes"; then + AC_DEFINE([HAVE_CONSENSUS_LIB], [1], [Define this symbol if the consensus lib has been built]) + AC_CONFIG_FILES([libbitcoinconsensus.pc:libbitcoinconsensus.pc.in]) +fi + AM_CONDITIONAL([BUILD_BITCOIN_KERNEL_LIB], [test "$build_experimental_kernel_lib" != "no" && ( test "$build_experimental_kernel_lib" = "yes" || test "$build_bitcoin_chainstate" = "yes" )]) +AC_MSG_RESULT($build_bitcoin_libs) + AC_LANG_POP if test "$use_ccache" != "no"; then @@ -1689,8 +1706,8 @@ else AC_MSG_RESULT([no]) fi -if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nonononononononono"; then - AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-daemon --with-gui --enable-fuzz(-binary) --enable-bench or --enable-tests]) +if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nononononononononono"; then + AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-fuzz(-binary) --enable-bench or --enable-tests]) fi AM_CONDITIONAL([TARGET_DARWIN], [test "$TARGET_OS" = "darwin"]) @@ -1846,6 +1863,7 @@ echo echo "Options used to compile and link:" echo " external signer = $use_external_signer" echo " multiprocess = $build_multiprocess" +echo " with libs = $build_bitcoin_libs" echo " with wallet = $enable_wallet" if test "$enable_wallet" != "no"; then echo " with sqlite = $use_sqlite" diff --git a/doc/README.md b/doc/README.md index 74a85b04e6..03f330a276 100644 --- a/doc/README.md +++ b/doc/README.md @@ -58,6 +58,7 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th - [Translation Strings Policy](translation_strings_policy.md) - [JSON-RPC Interface](JSON-RPC-interface.md) - [Unauthenticated REST Interface](REST-interface.md) +- [Shared Libraries](shared-libraries.md) - [BIPS](bips.md) - [Dnsseed Policy](dnsseed-policy.md) - [Benchmarking](benchmarking.md) diff --git a/doc/design/libraries.md b/doc/design/libraries.md index caf414ac47..946ecee52c 100644 --- a/doc/design/libraries.md +++ b/doc/design/libraries.md @@ -4,10 +4,11 @@ |--------------------------|-------------| | *libbitcoin_cli* | RPC client functionality used by *bitcoin-cli* executable | | *libbitcoin_common* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_util*, but higher-level (see [Dependencies](#dependencies)). | -| *libbitcoin_consensus* | Stable, backwards-compatible consensus functionality used by *libbitcoin_node* and *libbitcoin_wallet*. | +| *libbitcoin_consensus* | Stable, backwards-compatible consensus functionality used by *libbitcoin_node* and *libbitcoin_wallet* and also exposed as a [shared library](../shared-libraries.md). | +| *libbitcoinconsensus* | Shared library build of static *libbitcoin_consensus* library | | *libbitcoin_crypto* | Hardware-optimized functions for data encryption, hashing, message authentication, and key derivation. | -| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node*. | -| *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables. | +| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node* and also exposed as a [shared library](../shared-libraries.md). | +| *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables | | *libbitcoin_ipc* | IPC functionality used by *bitcoin-node*, *bitcoin-wallet*, *bitcoin-gui* executables to communicate when [`--enable-multiprocess`](multiprocess.md) is used. | | *libbitcoin_node* | P2P and RPC server functionality used by *bitcoind* and *bitcoin-qt* executables. | | *libbitcoin_util* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_common*, but lower-level (see [Dependencies](#dependencies)). | @@ -17,7 +18,7 @@ ## Conventions -- Most libraries are internal libraries and have APIs which are completely unstable! There are few or no restrictions on backwards compatibility or rules about external dependencies. An exception is *libbitcoin_kernel*, which, at some future point, will have a documented external interface. +- Most libraries are internal libraries and have APIs which are completely unstable! There are few or no restrictions on backwards compatibility or rules about external dependencies. Exceptions are *libbitcoin_consensus* and *libbitcoin_kernel* which have external interfaces documented at [../shared-libraries.md](../shared-libraries.md). - Generally each library should have a corresponding source directory and namespace. Source code organization is a work in progress, so it is true that some namespaces are applied inconsistently, and if you look at [`libbitcoin_*_SOURCES`](../../src/Makefile.am) lists you can see that many libraries pull in files from outside their source directory. But when working with libraries, it is good to follow a consistent pattern like: diff --git a/doc/shared-libraries.md b/doc/shared-libraries.md new file mode 100644 index 0000000000..3a448c6556 --- /dev/null +++ b/doc/shared-libraries.md @@ -0,0 +1,78 @@ +Shared Libraries +================ + +## bitcoinconsensus +***This library is deprecated and will be removed in v28*** + +The purpose of this library is to make the verification functionality that is critical to Bitcoin's consensus available to other applications, e.g. to language bindings. + +### API + +The interface is defined in the C header `bitcoinconsensus.h` located in `src/script/bitcoinconsensus.h`. + +#### Version + +`bitcoinconsensus_version` returns an `unsigned int` with the API version *(currently `2`)*. + +#### Script Validation + +`bitcoinconsensus_verify_script`, `bitcoinconsensus_verify_script_with_amount` and `bitcoinconsensus_verify_script_with_spent_outputs` return an `int` with the status of the verification. It will be `1` if the input script correctly spends the previous output `scriptPubKey`. + +##### Parameters +###### bitcoinconsensus_verify_script +- `const unsigned char *scriptPubKey` - The previous output script that encumbers spending. +- `unsigned int scriptPubKeyLen` - The number of bytes for the `scriptPubKey`. +- `const unsigned char *txTo` - The transaction with the input that is spending the previous output. +- `unsigned int txToLen` - The number of bytes for the `txTo`. +- `unsigned int nIn` - The index of the input in `txTo` that spends the `scriptPubKey`. +- `unsigned int flags` - The script validation flags *(see below)*. +- `bitcoinconsensus_error* err` - Will have the error/success code for the operation *(see below)*. + +###### bitcoinconsensus_verify_script_with_amount +- `const unsigned char *scriptPubKey` - The previous output script that encumbers spending. +- `unsigned int scriptPubKeyLen` - The number of bytes for the `scriptPubKey`. +- `int64_t amount` - The amount spent in the input +- `const unsigned char *txTo` - The transaction with the input that is spending the previous output. +- `unsigned int txToLen` - The number of bytes for the `txTo`. +- `unsigned int nIn` - The index of the input in `txTo` that spends the `scriptPubKey`. +- `unsigned int flags` - The script validation flags *(see below)*. +- `bitcoinconsensus_error* err` - Will have the error/success code for the operation *(see below)*. + +###### bitcoinconsensus_verify_script_with_spent_outputs +- `const unsigned char *scriptPubKey` - The previous output script that encumbers spending. +- `unsigned int scriptPubKeyLen` - The number of bytes for the `scriptPubKey`. +- `int64_t amount` - The amount spent in the input +- `const unsigned char *txTo` - The transaction with the input that is spending the previous output. +- `unsigned int txToLen` - The number of bytes for the `txTo`. +- `UTXO *spentOutputs` - Previous outputs spent in the transaction. `UTXO` is a struct composed by `const unsigned char *scriptPubKey`, `unsigned int scriptPubKeySize` (the number of bytes for the `scriptPubKey`) and `unsigned int value`. +- `unsigned int spentOutputsLen` - The number of bytes for the `spentOutputs`. +- `unsigned int nIn` - The index of the input in `txTo` that spends the `scriptPubKey`. +- `unsigned int flags` - The script validation flags *(see below)*. +- `bitcoinconsensus_error* err` - Will have the error/success code for the operation *(see below)*. + +##### Script Flags +- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE` +- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH` - Evaluate P2SH ([BIP16](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki)) subscripts +- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG` - Enforce strict DER ([BIP66](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki)) compliance +- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NULLDUMMY` - Enforce NULLDUMMY ([BIP147](https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki)) +- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY` - Enable CHECKLOCKTIMEVERIFY ([BIP65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki)) +- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY` - Enable CHECKSEQUENCEVERIFY ([BIP112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki)) +- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS` - Enable WITNESS ([BIP141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki)) +- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT` - Enable TAPROOT ([BIP340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki), [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki), [BIP342](https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki)) + +##### Errors +- `bitcoinconsensus_ERR_OK` - No errors with input parameters *(see the return value of `bitcoinconsensus_verify_script` for the verification status)* +- `bitcoinconsensus_ERR_TX_INDEX` - An invalid index for `txTo` +- `bitcoinconsensus_ERR_TX_SIZE_MISMATCH` - `txToLen` did not match with the size of `txTo` +- `bitcoinconsensus_ERR_DESERIALIZE` - An error deserializing `txTo` +- `bitcoinconsensus_ERR_AMOUNT_REQUIRED` - Input amount is required if WITNESS is used +- `bitcoinconsensus_ERR_INVALID_FLAGS` - Script verification `flags` are invalid (i.e. not part of the libconsensus interface) +- `bitcoinconsensus_ERR_SPENT_OUTPUTS_REQUIRED` - Spent outputs are required if TAPROOT is used +- `bitcoinconsensus_ERR_SPENT_OUTPUTS_MISMATCH` - Spent outputs size doesn't match tx inputs size + +### Example Implementations +- [NBitcoin](https://github.com/MetacoSA/NBitcoin/blob/5e1055cd7c4186dee4227c344af8892aea54faec/NBitcoin/Script.cs#L979-#L1031) (.NET Bindings) +- [node-libbitcoinconsensus](https://github.com/bitpay/node-libbitcoinconsensus) (Node.js Bindings) +- [java-libbitcoinconsensus](https://github.com/dexX7/java-libbitcoinconsensus) (Java Bindings) +- [bitcoinconsensus-php](https://github.com/Bit-Wasp/bitcoinconsensus-php) (PHP Bindings) +- [rust-bitcoinconsensus](https://github.com/rust-bitcoin/rust-bitcoinconsensus) (Rust Bindings) \ No newline at end of file diff --git a/libbitcoinconsensus.pc.in b/libbitcoinconsensus.pc.in new file mode 100644 index 0000000000..1ceab280bb --- /dev/null +++ b/libbitcoinconsensus.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: @PACKAGE_NAME@ consensus library +Description: Library for the Bitcoin consensus protocol. +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lbitcoinconsensus +Cflags: -I${includedir} diff --git a/src/Makefile.am b/src/Makefile.am index c1af30d264..bf4dcf8996 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,6 +43,9 @@ endif if ENABLE_ZMQ LIBBITCOIN_ZMQ=libbitcoin_zmq.a endif +if BUILD_BITCOIN_LIBS +LIBBITCOINCONSENSUS=libbitcoinconsensus.la +endif if BUILD_BITCOIN_KERNEL_LIB LIBBITCOINKERNEL=libbitcoinkernel.la endif @@ -663,6 +666,7 @@ libbitcoin_consensus_a_SOURCES = \ primitives/transaction.h \ pubkey.cpp \ pubkey.h \ + script/bitcoinconsensus.cpp \ script/interpreter.cpp \ script/interpreter.h \ script/script.cpp \ @@ -1009,6 +1013,21 @@ libbitcoinkernel_la-clientversion.l$(OBJEXT): obj/build.h endif # BUILD_BITCOIN_KERNEL_LIB # +# bitcoinconsensus library # +if BUILD_BITCOIN_LIBS +lib_LTLIBRARIES += $(LIBBITCOINCONSENSUS) + +include_HEADERS = script/bitcoinconsensus.h +libbitcoinconsensus_la_SOURCES = $(crypto_libbitcoin_crypto_base_la_SOURCES) $(libbitcoin_consensus_a_SOURCES) + +libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) +libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1) +libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj $(libsecp256k1_CFLAGS) -DBUILD_BITCOIN_INTERNAL -DDISABLE_OPTIMIZED_SHA256 +libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) + +endif +# + CTAES_DIST = crypto/ctaes/bench.c CTAES_DIST += crypto/ctaes/ctaes.c CTAES_DIST += crypto/ctaes/ctaes.h diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 233f1a1c21..7e6d24d913 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -376,6 +376,7 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/rpc.cpp \ test/fuzz/script.cpp \ test/fuzz/script_assets_test_minimizer.cpp \ + test/fuzz/script_bitcoin_consensus.cpp \ test/fuzz/script_descriptor_cache.cpp \ test/fuzz/script_flags.cpp \ test/fuzz/script_format.cpp \ diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp index f38aa49a23..81139feb47 100644 --- a/src/bench/verify_script.cpp +++ b/src/bench/verify_script.cpp @@ -2,8 +2,15 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include +#if defined(HAVE_CONSENSUS_LIB) +#include