diff --git a/doc/release-notes.md b/doc/release-notes.md
index 1d3daba934..688a325d2d 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,21 +1,27 @@
Bitcoin ABC version 0.21.3 is now available from:
This release includes the following features and fixes:
- Fixed a bug where the `listtransactions` RPC was unable to list transactions
by a giving label. This functionality has been restored.
- MacOS versions earlier than 10.12 are no longer supported.
Additionally, Bitcoin ABC does not yet change appearance when macOS
"dark mode" is activated.
New RPC methods
------------
- `listwalletdir` returns a list of wallets in the wallet directory which is
configured with `-walletdir` parameter.
Low-level RPC changes
----------------------
- `-usehd` was removed in version 0.16. From that version onwards, all new
wallets created are hierarchical deterministic wallets. Version 0.18 makes
specifying `-usehd` invalid config.
+
+Thread names in logs
+--------------------
+
+Log lines can be prefixed with the name of the thread that caused the log.
+To enable this behavior, use`-logthreadnames=1`.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6012f4a628..8b489f4faa 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,620 +1,621 @@
# Copyright (c) 2017 The Bitcoin developers
project(bitcoind)
set(CMAKE_CXX_STANDARD 14)
# Default visibility is hidden on all targets.
set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
option(BUILD_BITCOIN_WALLET "Activate the wallet functionality" ON)
option(BUILD_BITCOIN_ZMQ "Activate the ZeroMQ functionalities" ON)
option(BUILD_BITCOIN_SEEDER "Build bitcoin-seeder" ON)
option(BUILD_BITCOIN_CLI "Build bitcoin-cli" ON)
option(BUILD_BITCOIN_TX "Build bitcoin-tx" ON)
option(BUILD_BITCOIN_QT "Build bitcoin-qt" ON)
option(BUILD_LIBBITCOINCONSENSUS "Build the bitcoinconsenus shared library" ON)
option(ENABLE_BIP70 "Enable BIP70 (payment protocol) support in GUI" ON)
option(ENABLE_HARDENING "Harden the executables" ON)
option(ENABLE_REDUCE_EXPORTS "Reduce the amount of exported symbols" OFF)
option(ENABLE_STATIC_LIBSTDCXX "Statically link libstdc++" OFF)
option(ENABLE_GLIBC_BACK_COMPAT "Enable Glibc compatibility features" OFF)
option(ENABLE_QRCODE "Enable QR code display" ON)
option(ENABLE_UPNP "Enable UPnP support" ON)
option(ENABLE_NOTIFICATIONS "Enable desktop notifications" ON)
option(ENABLE_WERROR "Promote some compiler warnings to errors" OFF)
option(START_WITH_UPNP "Make UPnP the default to map ports" OFF)
option(ENABLE_CLANG_TIDY "Enable clang-tidy checks for Bitcoin ABC" OFF)
option(ENABLE_PROFILING "Select the profiling tool to use" OFF)
option(USE_LD_GOLD "Try to use gold as a linker if available" ON)
# If ccache is available, then use it.
find_program(CCACHE ccache)
if(CCACHE)
message(STATUS "Using ccache: ${CCACHE}")
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE})
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
endif(CCACHE)
# Disable what we do not need for the native build.
include(NativeExecutable)
native_add_cmake_flags(
"-DBUILD_BITCOIN_WALLET=OFF"
"-DBUILD_BITCOIN_QT=OFF"
"-DBUILD_BITCOIN_ZMQ=OFF"
"-DENABLE_QRCODE=OFF"
"-DENABLE_UPNP=OFF"
# Forward the current setting for clang-tidy
"-DENABLE_CLANG_TIDY=${ENABLE_CLANG_TIDY}"
)
if(ENABLE_CLANG_TIDY)
include(ClangTidy)
endif()
if(ENABLE_SANITIZERS)
include(Sanitizers)
enable_sanitizers(${ENABLE_SANITIZERS})
endif()
include(AddCompilerFlags)
if(USE_LD_GOLD)
add_linker_flags(-fuse-ld=gold)
endif()
# Prefer -g3, defaults to -g if unavailable
foreach(LANGUAGE C CXX)
set(COMPILER_DEBUG_LEVEL -g)
check_compiler_flag(G3_IS_SUPPORTED ${LANGUAGE} -g3)
if(${G3_IS_SUPPORTED})
set(COMPILER_DEBUG_LEVEL -g3)
endif()
add_compile_options_to_configuration_for_language(Debug ${LANGUAGE} ${COMPILER_DEBUG_LEVEL})
endforeach()
# Define the debugging symbols DEBUG and DEBUG_LOCKORDER when the Debug build
# type is selected.
add_compile_definitions_to_configuration(Debug DEBUG DEBUG_LOCKORDER)
# Add -ftrapv when building in Debug
add_compile_options_to_configuration(Debug -ftrapv)
# All versions of gcc that we commonly use for building are subject to bug
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90348. To work around that, set
# -fstack-reuse=none for all gcc builds. (Only gcc understands this flag)
if(NOT ENABLE_CLANG_TIDY)
add_compiler_flags(-fstack-reuse=none)
endif()
# Ensure that WINDRES_PREPROC is enabled when using windres.
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
# Ensure that WINDRES_PREPROC is enabled when using windres.
list(APPEND CMAKE_RC_FLAGS "-DWINDRES_PREPROC")
# Build all static so there is no dll file to distribute.
add_linker_flags(-static)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
add_compile_definitions(MAC_OSX OBJC_OLD_DISPATCH_PROTOTYPES=0)
endif()
if(ENABLE_REDUCE_EXPORTS)
# Default visibility is set by CMAKE__VISIBILITY_PRESET, but this
# doesn't tell if the visibility set is effective.
# Check if the flag -fvisibility=hidden is supported, as using the hidden
# visibility is a requirement to reduce exports.
check_compiler_flag(HAS_CXX_FVISIBILITY CXX -fvisibility=hidden)
if(NOT HAS_CXX_FVISIBILITY)
message(FATAL_ERROR "Cannot set default symbol visibility. Use -DENABLE_REDUCE_EXPORTS=OFF.")
endif()
# Also hide symbols from static libraries
add_linker_flags(-Wl,--exclude-libs,ALL)
endif()
# Enable statically linking libstdc++
if(ENABLE_STATIC_LIBSTDCXX)
add_linker_flags(-static-libstdc++)
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
if(ENABLE_HARDENING)
# Enable stack protection
add_cxx_compiler_flags(-fstack-protector-all -Wstack-protector)
# Enable some buffer overflow checking
add_compiler_flags(-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2)
# Enable ASLR (these flags are primarily targeting MinGw)
add_linker_flags(-Wl,--dynamicbase -Wl,--nxcompat -Wl,--high-entropy-va)
# Make the relocated sections read-only
add_linker_flags(-Wl,-z,relro -Wl,-z,now)
# CMake provides the POSITION_INDEPENDENT_CODE property to set PIC/PIE.
# Unfortunately setting the -pie linker flag this way require CMake >= 3.14,
# which is not widely distributed at the time of writing.
# FIXME: remove the fallback case when cmake >= 3.14 get enforced.
if(POLICY CMP0083)
cmake_policy(SET CMP0083 NEW)
include(CheckPIESupported)
check_pie_supported()
elseif(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows")
add_linker_flags(-pie)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
# MinGw provides its own libssp for stack smashing protection
link_libraries(ssp)
endif()
endif()
if(ENABLE_PROFILING MATCHES "gprof")
message(STATUS "Enable profiling with gprof")
# -pg is incompatible with -pie. Since hardening and profiling together
# doesn't make sense, we simply make them mutually exclusive here.
# Additionally, hardened toolchains may force -pie by default, in which
# case it needs to be turned off with -no-pie.
if(ENABLE_HARDENING)
message(FATAL_ERROR "Profiling with gprof requires disabling hardening with -DENABLE_HARDENING=OFF.")
endif()
add_linker_flags(-no-pie)
add_compiler_flags(-pg)
add_linker_flags(-pg)
endif()
# Enable warning
add_c_compiler_flags(-Wnested-externs -Wstrict-prototypes)
add_compiler_flags(
-Wall
-Wextra
-Wformat
-Wvla
-Wformat-security
-Wcast-align
-Wunused-parameter
-Wmissing-braces
-Wthread-safety-analysis
-Wshadow
-Wrange-loop-analysis
-Wredundant-decls
-Wredundant-move
)
option(EXTRA_WARNINGS "Enable extra warnings" OFF)
if(EXTRA_WARNINGS)
add_cxx_compiler_flags(-Wsuggest-override)
else()
add_compiler_flags(-Wno-unused-parameter)
add_compiler_flags(-Wno-implicit-fallthrough)
endif()
if(ENABLE_WERROR)
add_compiler_flags(
-Werror=vla
-Werror=thread-safety-analysis
)
endif()
# Create a target for OpenSSL
include(BrewHelper)
find_brew_prefix(OPENSSL_ROOT_DIR openssl)
find_package(OpenSSL REQUIRED)
# libtool style configure
add_subdirectory(config)
# libraries
add_subdirectory(crypto)
add_subdirectory(leveldb)
add_subdirectory(secp256k1)
add_subdirectory(univalue)
# Find the git root, and returns the full path to the .git/logs/HEAD file if
# it exists.
function(find_git_head_logs_file RESULT)
find_package(Git)
if(GIT_FOUND)
execute_process(
COMMAND "${GIT_EXECUTABLE}" "rev-parse" "--show-toplevel"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_VARIABLE GIT_ROOT
RESULT_VARIABLE GIT_RESULT
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
if(GIT_RESULT EQUAL 0)
set(GIT_LOGS_DIR "${GIT_ROOT}/.git/logs")
set(GIT_HEAD_LOGS_FILE "${GIT_LOGS_DIR}/HEAD")
# If the .git/logs/HEAD does not exist, create it
if(NOT EXISTS "${GIT_HEAD_LOGS_FILE}")
file(MAKE_DIRECTORY "${GIT_LOGS_DIR}")
file(TOUCH "${GIT_HEAD_LOGS_FILE}")
endif()
set(${RESULT} "${GIT_HEAD_LOGS_FILE}" PARENT_SCOPE)
endif()
endif()
endfunction()
find_git_head_logs_file(GIT_HEAD_LOGS_FILE)
set(OBJ_DIR "${CMAKE_CURRENT_BINARY_DIR}/obj")
file(MAKE_DIRECTORY "${OBJ_DIR}")
set(BUILD_HEADER "${OBJ_DIR}/build.h")
set(BUILD_HEADER_TMP "${BUILD_HEADER}.tmp")
add_custom_command(
DEPENDS
"${GIT_HEAD_LOGS_FILE}"
"${CMAKE_SOURCE_DIR}/share/genbuild.sh"
OUTPUT
"${BUILD_HEADER}"
COMMAND
"${CMAKE_SOURCE_DIR}/share/genbuild.sh"
"${BUILD_HEADER_TMP}"
"${CMAKE_SOURCE_DIR}"
COMMAND
${CMAKE_COMMAND} -E copy_if_different "${BUILD_HEADER_TMP}" "${BUILD_HEADER}"
COMMAND
${CMAKE_COMMAND} -E remove "${BUILD_HEADER_TMP}"
)
# Because the Bitcoin ABc source code is disorganised, we
# end up with a bunch of libraries without any apparent
# cohesive structure. This is inherited from Bitcoin Core
# and reflecting this.
# TODO: Improve the structure once cmake is rocking.
# Various completely unrelated features shared by all executables.
add_library(util
chainparamsbase.cpp
clientversion.cpp
compat/glibc_sanity.cpp
compat/glibcxx_sanity.cpp
compat/strnlen.cpp
fs.cpp
logging.cpp
random.cpp
rcu.cpp
rpc/protocol.cpp
rpc/util.cpp
support/cleanse.cpp
support/lockedpool.cpp
sync.cpp
threadinterrupt.cpp
uint256.cpp
- util/system.cpp
+ util/bytevectorhash.cpp
util/moneystr.cpp
util/strencodings.cpp
+ util/system.cpp
+ util/threadnames.cpp
util/time.cpp
- util/bytevectorhash.cpp
# obj/build.h
"${BUILD_HEADER}"
)
target_compile_definitions(util PUBLIC HAVE_CONFIG_H HAVE_BUILD_INFO)
target_include_directories(util
PUBLIC
.
# To access the config/ and obj/ directories
${CMAKE_CURRENT_BINARY_DIR}
)
if(ENABLE_GLIBC_BACK_COMPAT)
# glibc absorbed clock_gettime in 2.17. librt (its previous location) is
# safe to link in anyway for back-compat.
find_library(RT_LIBRARY rt)
target_link_libraries(util ${RT_LIBRARY})
# Wrap some glibc functions with ours
add_linker_flags(-Wl,--wrap=__divmoddi4)
add_linker_flags(-Wl,--wrap=log2f)
if(NOT HAVE_LARGE_FILE_SUPPORT)
add_linker_flags(-Wl,--wrap=fcntl -Wl,--wrap=fcntl64)
endif()
target_sources(util PRIVATE compat/glibc_compat.cpp)
endif()
# Enable LFS (Large File Support) on targets that don't have it natively.
if(NOT HAVE_LARGE_FILE_SUPPORT)
add_compiler_flags(-D_FILE_OFFSET_BITS=64)
add_linker_flags(-Wl,--large-address-aware)
endif()
# Target specific configs
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(Boost_USE_STATIC_LIBS ON)
set(Boost_THREADAPI win32)
find_package(SHLWAPI REQUIRED)
# We cannot use the imported target here, because cmake will introduce an
# -isystem compilation directive and cause the build to fail with MinGw.
# This comes from a couple cmake bugs:
# - https://gitlab.kitware.com/cmake/cmake/issues/16291
# - https://gitlab.kitware.com/cmake/cmake/issues/19095
# These issues are solved from cmake 3.14.1. Once this version is enforced,
# the following can be used:
# target_link_libraries(util SHLWAPI::shlwapi)
target_link_libraries(util ${SHLWAPI_LIBRARIES})
target_include_directories(util PUBLIC ${SHLWAPI_INCLUDE_DIRS})
find_library(WS2_32_LIBRARY NAMES ws2_32)
target_link_libraries(util ${WS2_32_LIBRARY})
target_compile_definitions(util PUBLIC BOOST_THREAD_USE_LIB)
endif()
# Boost packages
set(BOOST_PACKAGES_REQUIRED chrono filesystem thread)
function(prepend var prefix)
set(listVar "")
foreach(f ${ARGN})
list(APPEND listVar "${prefix}${f}")
endforeach(f)
set(${var} "${listVar}" PARENT_SCOPE)
endfunction(prepend)
prepend(BOOST_LIBRARIES "Boost::" ${BOOST_PACKAGES_REQUIRED})
find_package(Boost 1.58 REQUIRED ${BOOST_PACKAGES_REQUIRED})
target_link_libraries(util univalue crypto ${BOOST_LIBRARIES})
# Make sure boost uses std::atomic (it doesn't before 1.63)
target_compile_definitions(util PUBLIC BOOST_SP_USE_STD_ATOMIC BOOST_AC_USE_STD_ATOMIC)
# More completely unrelated features shared by all executables.
# Because nothing says this is different from util than "common"
add_library(common
amount.cpp
base58.cpp
cashaddr.cpp
cashaddrenc.cpp
chainparams.cpp
config.cpp
consensus/merkle.cpp
coins.cpp
compressor.cpp
feerate.cpp
globals.cpp
core_read.cpp
core_write.cpp
key.cpp
key_io.cpp
keystore.cpp
netaddress.cpp
netbase.cpp
primitives/block.cpp
protocol.cpp
scheduler.cpp
versionbitsinfo.cpp
warnings.cpp
)
target_link_libraries(common util secp256k1)
# script library
add_library(script
script/bitfield.cpp
script/descriptor.cpp
script/interpreter.cpp
script/ismine.cpp
script/script.cpp
script/script_error.cpp
script/sigencoding.cpp
script/sign.cpp
script/standard.cpp
)
target_link_libraries(script common)
# libbitcoinconsensus
add_library(bitcoinconsensus
arith_uint256.cpp
hash.cpp
primitives/transaction.cpp
pubkey.cpp
uint256.cpp
util/strencodings.cpp
)
target_link_libraries(bitcoinconsensus script)
include(InstallationHelper)
if(BUILD_LIBBITCOINCONSENSUS)
target_compile_definitions(bitcoinconsensus
PUBLIC
BUILD_BITCOIN_INTERNAL
HAVE_CONSENSUS_LIB
)
install_shared_library(bitcoinconsensus
script/bitcoinconsensus.cpp
PUBLIC_HEADER script/bitcoinconsensus.h
)
endif()
# Bitcoin server facilities
add_library(server
addrdb.cpp
addrman.cpp
avalanche.cpp
banman.cpp
bloom.cpp
blockencodings.cpp
blockfilter.cpp
chain.cpp
checkpoints.cpp
config.cpp
consensus/activation.cpp
consensus/tx_verify.cpp
dbwrapper.cpp
flatfile.cpp
globals.cpp
httprpc.cpp
httpserver.cpp
index/base.cpp
index/txindex.cpp
init.cpp
interfaces/chain.cpp
interfaces/handler.cpp
interfaces/node.cpp
merkleblock.cpp
miner.cpp
minerfund.cpp
net.cpp
net_processing.cpp
noui.cpp
outputtype.cpp
policy/fees.cpp
policy/mempool.cpp
policy/policy.cpp
pow.cpp
rest.cpp
rpc/abc.cpp
rpc/blockchain.cpp
rpc/command.cpp
rpc/jsonrpcrequest.cpp
rpc/mining.cpp
rpc/misc.cpp
rpc/net.cpp
rpc/rawtransaction.cpp
rpc/server.cpp
script/scriptcache.cpp
script/sigcache.cpp
shutdown.cpp
timedata.cpp
torcontrol.cpp
txdb.cpp
txmempool.cpp
ui_interface.cpp
validation.cpp
validationinterface.cpp
versionbits.cpp
)
target_include_directories(server PRIVATE leveldb/helpers/memenv)
# This require libevent
set(EVENT_MIN_VERSION 2.0.22)
find_package(Event ${EVENT_MIN_VERSION} REQUIRED COMPONENTS event)
target_link_libraries(server
Event::event
bitcoinconsensus
leveldb
memenv
)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows")
find_package(Event ${EVENT_MIN_VERSION} REQUIRED COMPONENTS pthreads)
target_link_libraries(server Event::pthreads)
endif()
if(ENABLE_UPNP)
find_package(MiniUPnPc 1.5 REQUIRED)
target_link_libraries(server MiniUPnPc::miniupnpc)
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
find_library(IPHLPAPI_LIBRARY NAMES iphlpapi)
if(NOT IPHLPAPI_LIBRARY)
message(FATAL_ERROR "Lib iphlpapi is missing")
endif()
target_link_libraries(server ${IPHLPAPI_LIBRARY})
target_compile_definitions(server
PUBLIC -DSTATICLIB
PUBLIC -DMINIUPNP_STATICLIB
)
endif()
endif()
# Test suite.
add_subdirectory(test)
# Benchmark suite.
add_subdirectory(bench)
# Wallet
if(BUILD_BITCOIN_WALLET)
add_subdirectory(wallet)
target_link_libraries(server wallet)
# There is a circular dependency between wallet and server, see:
# https://github.com/bitcoin/bitcoin/pull/14437#discussion_r226237048
target_link_libraries(wallet server)
else()
target_sources(server PRIVATE dummywallet.cpp)
endif()
# ZeroMQ
if(BUILD_BITCOIN_ZMQ)
add_subdirectory(zmq)
target_link_libraries(server zmq)
endif()
# RPC client support
add_library(rpcclient rpc/client.cpp)
target_link_libraries(rpcclient univalue util)
# bitcoin-seeder
if(BUILD_BITCOIN_SEEDER)
add_subdirectory(seeder)
endif()
include(BinaryTest)
# bitcoin-cli
if(BUILD_BITCOIN_CLI)
add_executable(bitcoin-cli bitcoin-cli.cpp)
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
target_sources(bitcoin-cli PRIVATE bitcoin-cli-res.rc)
endif()
target_link_libraries(bitcoin-cli common rpcclient Event::event)
add_to_symbols_check(bitcoin-cli)
add_to_security_check(bitcoin-cli)
install_target(bitcoin-cli)
endif()
# bitcoin-tx
if(BUILD_BITCOIN_TX)
add_executable(bitcoin-tx bitcoin-tx.cpp)
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
target_sources(bitcoin-tx PRIVATE bitcoin-tx-res.rc)
endif()
target_link_libraries(bitcoin-tx bitcoinconsensus)
add_to_symbols_check(bitcoin-tx)
add_to_security_check(bitcoin-tx)
install_target(bitcoin-tx)
endif()
# bitcoind
add_executable(bitcoind bitcoind.cpp)
target_link_libraries(bitcoind server)
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
target_sources(bitcoind PRIVATE bitcoind-res.rc)
endif()
add_to_symbols_check(bitcoind)
add_to_security_check(bitcoind)
install_target(bitcoind)
# Bitcoin-qt
if(BUILD_BITCOIN_QT)
add_subdirectory(qt)
endif()
diff --git a/src/Makefile.am b/src/Makefile.am
index 58196b9dcf..a79e53c956 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,713 +1,715 @@
# Copyright (c) 2013-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
DIST_SUBDIRS = secp256k1 univalue
AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS)
AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS)
AM_CPPFLAGS = $(DEBUG_CPPFLAGS) $(HARDENED_CPPFLAGS)
AM_LIBTOOLFLAGS = --preserve-dup-deps
EXTRA_LIBRARIES =
if EMBEDDED_UNIVALUE
LIBUNIVALUE = univalue/libunivalue.la
$(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*)
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F)
else
LIBUNIVALUE = $(UNIVALUE_LIBS)
endif
BITCOIN_INCLUDES=-I$(builddir) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS)
BITCOIN_SEEDER_INCLUDES = -I$(srcdir)/seeder
BITCOIN_SEEDER_INCLUDES += $(BITCOIN_INCLUDES)
LIBBITCOIN_SERVER=libbitcoin_server.a
LIBBITCOIN_COMMON=libbitcoin_common.a
LIBBITCOIN_CONSENSUS=libbitcoin_consensus.a
LIBBITCOIN_CLI=libbitcoin_cli.a
LIBBITCOIN_UTIL=libbitcoin_util.a
LIBBITCOIN_CRYPTO_BASE=crypto/libbitcoin_crypto_base.a
LIBBITCOINQT=qt/libbitcoinqt.a
LIBSECP256K1=secp256k1/libsecp256k1.la
if ENABLE_ZMQ
LIBBITCOIN_ZMQ=libbitcoin_zmq.a
endif
if BUILD_BITCOIN_LIBS
LIBBITCOINCONSENSUS=libbitcoinconsensus.la
endif
if BUILD_BITCOIN_SEEDER
LIBBITCOIN_SEEDER=libbitcoin_seeder.a
endif
if ENABLE_WALLET
LIBBITCOIN_WALLET=libbitcoin_wallet.a
endif
LIBBITCOIN_CRYPTO= $(LIBBITCOIN_CRYPTO_BASE)
if ENABLE_SSE41
LIBBITCOIN_CRYPTO_SSE41 = crypto/libbitcoin_crypto_sse41.a
LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_SSE41)
endif
if ENABLE_AVX2
LIBBITCOIN_CRYPTO_AVX2 = crypto/libbitcoin_crypto_avx2.a
LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_AVX2)
endif
if ENABLE_SHANI
LIBBITCOIN_CRYPTO_SHANI = crypto/libbitcoin_crypto_shani.a
LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_SHANI)
endif
$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*)
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F)
# Make is not made aware of per-object dependencies to avoid limiting building parallelization
# But to build the less dependent modules first, we manually select their order here:
EXTRA_LIBRARIES += \
$(LIBBITCOIN_CRYPTO) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_CLI) \
$(LIBBITCOIN_SEEDER) \
$(LIBBITCOIN_WALLET) \
$(LIBBITCOIN_ZMQ)
lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS)
bin_PROGRAMS =
noinst_PROGRAMS =
TESTS =
BENCHMARKS =
if BUILD_BITCOIND
bin_PROGRAMS += bitcoind
endif
if BUILD_BITCOIN_SEEDER
bin_PROGRAMS += bitcoin-seeder
endif
if BUILD_BITCOIN_UTILS
bin_PROGRAMS += bitcoin-cli bitcoin-tx
endif
.PHONY: FORCE check-symbols check-security
# bitcoin core #
BITCOIN_CORE_H = \
addrdb.h \
addrman.h \
attributes.h \
avalanche.h \
banman.h \
base58.h \
bloom.h \
blockencodings.h \
blockfileinfo.h \
blockfilter.h \
blockindexworkcomparator.h \
blockstatus.h \
blockvalidity.h \
cashaddr.h \
cashaddrenc.h \
chain.h \
chainparams.h \
chainparamsbase.h \
chainparamsconstants.h \
chainparamsseeds.h \
checkpoints.h \
checkqueue.h \
clientversion.h \
coins.h \
compat.h \
compat/assumptions.h \
compat/byteswap.h \
compat/endian.h \
compat/sanity.h \
compat/setenv.h \
compressor.h \
config.h \
consensus/activation.h \
consensus/consensus.h \
consensus/tx_verify.h \
core_io.h \
core_memusage.h \
cuckoocache.h \
flatfile.h \
fs.h \
globals.h \
httprpc.h \
httpserver.h \
index/base.h \
index/txindex.h \
indirectmap.h \
init.h \
interfaces/chain.h \
interfaces/handler.h \
interfaces/node.h \
interfaces/wallet.h \
key.h \
key_io.h \
keystore.h \
dbwrapper.h \
limitedmap.h \
logging.h \
memusage.h \
merkleblock.h \
miner.h \
minerfund.h \
net.h \
net_processing.h \
netaddress.h \
netbase.h \
netmessagemaker.h \
noui.h \
outputtype.h \
policy/fees.h \
policy/mempool.h \
policy/policy.h \
pow.h \
protocol.h \
radix.h \
random.h \
rcu.h \
reverse_iterator.h \
reverselock.h \
rpc/blockchain.h \
rpc/client.h \
rpc/command.h \
rpc/jsonrpcrequest.h \
rpc/mining.h \
rpc/protocol.h \
rpc/rawtransaction.h \
rpc/server.h \
rpc/register.h \
rpc/util.h \
rwcollection.h \
scheduler.h \
script/descriptor.h \
script/ismine.h \
script/scriptcache.h \
script/sigcache.h \
script/sign.h \
script/standard.h \
shutdown.h \
streams.h \
support/allocators/secure.h \
support/allocators/zeroafterfree.h \
support/cleanse.h \
support/events.h \
support/lockedpool.h \
sync.h \
threadsafety.h \
threadinterrupt.h \
timedata.h \
torcontrol.h \
txdb.h \
txmempool.h \
ui_interface.h \
undo.h \
- util/system.h \
- util/moneystr.h \
- util/time.h \
util/bitmanip.h \
util/bytevectorhash.h \
+ util/moneystr.h \
+ util/system.h \
+ util/threadnames.h \
+ util/time.h \
validation.h \
validationinterface.h \
versionbits.h \
versionbitsinfo.h \
walletinitinterface.h \
wallet/coincontrol.h \
wallet/coinselection.h \
wallet/crypter.h \
wallet/db.h \
wallet/finaltx.h \
wallet/rpcdump.h \
wallet/fees.h \
wallet/rpcwallet.h \
wallet/wallet.h \
wallet/walletdb.h \
wallet/walletutil.h \
warnings.h \
zmq/zmqabstractnotifier.h \
zmq/zmqconfig.h\
zmq/zmqnotificationinterface.h \
zmq/zmqpublishnotifier.h \
zmq/zmqrpc.h
obj/build.h: FORCE
@$(MKDIR_P) "$(builddir)/obj"
@$(top_srcdir)/share/genbuild.sh "$(abs_top_builddir)/src/obj/build.h" \
"$(abs_top_srcdir)"
libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
# server: shared between bitcoind and bitcoin-qt
libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
addrdb.cpp \
addrman.cpp \
avalanche.cpp \
banman.cpp \
bloom.cpp \
blockencodings.cpp \
blockfilter.cpp \
chain.cpp \
checkpoints.cpp \
config.cpp \
consensus/activation.cpp \
consensus/tx_verify.cpp \
flatfile.cpp \
globals.cpp \
httprpc.cpp \
httpserver.cpp \
index/base.cpp \
index/txindex.cpp \
init.cpp \
interfaces/chain.cpp \
interfaces/handler.cpp \
interfaces/node.cpp \
dbwrapper.cpp \
merkleblock.cpp \
miner.cpp \
minerfund.cpp \
net.cpp \
net_processing.cpp \
noui.cpp \
outputtype.cpp \
policy/fees.cpp \
policy/mempool.cpp \
policy/policy.cpp \
pow.cpp \
rest.cpp \
rpc/abc.cpp \
rpc/blockchain.cpp \
rpc/command.cpp \
rpc/jsonrpcrequest.cpp \
rpc/mining.cpp \
rpc/misc.cpp \
rpc/net.cpp \
rpc/rawtransaction.cpp \
rpc/server.cpp \
script/scriptcache.cpp \
script/sigcache.cpp \
shutdown.cpp \
timedata.cpp \
torcontrol.cpp \
txdb.cpp \
txmempool.cpp \
ui_interface.cpp \
validation.cpp \
validationinterface.cpp \
versionbits.cpp \
$(BITCOIN_CORE_H)
if !ENABLE_WALLET
libbitcoin_server_a_SOURCES += dummywallet.cpp
endif
if ENABLE_ZMQ
libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS)
libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_zmq_a_SOURCES = \
zmq/zmqabstractnotifier.cpp \
zmq/zmqnotificationinterface.cpp \
zmq/zmqpublishnotifier.cpp \
zmq/zmqrpc.cpp
endif
# wallet: shared between bitcoind and bitcoin-qt, but only linked
# when wallet enabled
libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_wallet_a_SOURCES = \
interfaces/wallet.cpp \
wallet/coincontrol.cpp \
wallet/crypter.cpp \
wallet/coinselection.cpp \
wallet/db.cpp \
wallet/finaltx.cpp \
wallet/fees.cpp \
wallet/init.cpp \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
wallet/wallet.cpp \
wallet/walletdb.cpp \
wallet/walletutil.cpp \
$(BITCOIN_CORE_H)
# crypto primitives library
crypto_libbitcoin_crypto_base_a_CPPFLAGS = $(AM_CPPFLAGS)
crypto_libbitcoin_crypto_base_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_base_a_SOURCES = \
crypto/aes.cpp \
crypto/aes.h \
crypto/chacha20.h \
crypto/chacha20.cpp \
crypto/common.h \
crypto/hmac_sha256.cpp \
crypto/hmac_sha256.h \
crypto/hmac_sha512.cpp \
crypto/hmac_sha512.h \
crypto/ripemd160.cpp \
crypto/ripemd160.h \
crypto/sha1.cpp \
crypto/sha1.h \
crypto/sha256.cpp \
crypto/sha256.h \
crypto/sha512.cpp \
crypto/sha512.h \
crypto/siphash.cpp \
crypto/siphash.h
if USE_ASM
crypto_libbitcoin_crypto_base_a_SOURCES += crypto/sha256_sse4.cpp
endif
crypto_libbitcoin_crypto_sse41_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_sse41_a_CPPFLAGS = $(AM_CPPFLAGS)
crypto_libbitcoin_crypto_sse41_a_CXXFLAGS += $(SSE41_CXXFLAGS)
crypto_libbitcoin_crypto_sse41_a_CPPFLAGS += -DENABLE_SSE41
crypto_libbitcoin_crypto_sse41_a_SOURCES = crypto/sha256_sse41.cpp
crypto_libbitcoin_crypto_avx2_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_avx2_a_CPPFLAGS = $(AM_CPPFLAGS)
crypto_libbitcoin_crypto_avx2_a_CXXFLAGS += $(AVX2_CXXFLAGS)
crypto_libbitcoin_crypto_avx2_a_CPPFLAGS += -DENABLE_AVX2
crypto_libbitcoin_crypto_avx2_a_SOURCES = crypto/sha256_avx2.cpp
crypto_libbitcoin_crypto_shani_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_shani_a_CPPFLAGS = $(AM_CPPFLAGS)
crypto_libbitcoin_crypto_shani_a_CXXFLAGS += $(SHANI_CXXFLAGS)
crypto_libbitcoin_crypto_shani_a_CPPFLAGS += -DENABLE_SHANI
crypto_libbitcoin_crypto_shani_a_SOURCES = crypto/sha256_shani.cpp
# consensus: shared between all executables that validate any consensus rules.
libbitcoin_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_consensus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_consensus_a_SOURCES = \
amount.h \
arith_uint256.cpp \
arith_uint256.h \
consensus/merkle.cpp \
consensus/merkle.h \
consensus/params.h \
consensus/validation.h \
feerate.h \
hash.cpp \
hash.h \
prevector.h \
primitives/block.cpp \
primitives/block.h \
primitives/transaction.cpp \
primitives/transaction.h \
primitives/txid.h \
pubkey.cpp \
pubkey.h \
script/bitcoinconsensus.cpp \
script/bitfield.cpp \
script/bitfield.h \
script/sighashtype.h \
script/interpreter.cpp \
script/interpreter.h \
script/script.cpp \
script/script.h \
script/script_error.cpp \
script/script_error.h \
script/script_flags.h \
script/script_metrics.h \
script/sigencoding.cpp \
script/sigencoding.h \
serialize.h \
span.h \
tinyformat.h \
uint256.cpp \
uint256.h \
util/strencodings.cpp \
util/strencodings.h \
version.h
# common: shared between bitcoind, and bitcoin-qt and non-server tools
libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_common_a_SOURCES = \
amount.cpp \
base58.cpp \
cashaddr.cpp \
cashaddrenc.cpp \
chainparams.cpp \
config.cpp \
coins.cpp \
compressor.cpp \
feerate.cpp \
globals.cpp \
core_read.cpp \
core_write.cpp \
key.cpp \
key_io.cpp \
keystore.cpp \
netaddress.cpp \
netbase.cpp \
protocol.cpp \
scheduler.cpp \
script/descriptor.cpp \
script/ismine.cpp \
script/sign.cpp \
script/standard.cpp \
versionbitsinfo.cpp \
warnings.cpp \
$(BITCOIN_CORE_H)
# util: shared between all executables.
# This library *must* be included to make sure that the glibc
# backward-compatibility objects and their sanity checks are linked.
libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_util_a_SOURCES = \
support/lockedpool.cpp \
chainparamsbase.cpp \
clientversion.cpp \
compat/glibc_sanity.cpp \
compat/glibcxx_sanity.cpp \
compat/strnlen.cpp \
fs.cpp \
logging.cpp \
random.cpp \
rcu.cpp \
rpc/protocol.cpp \
rpc/util.cpp \
support/cleanse.cpp \
sync.cpp \
threadinterrupt.cpp \
uint256.cpp \
uint256.h \
util/system.cpp \
util/moneystr.cpp \
util/strencodings.cpp \
+ util/threadnames.cpp \
util/time.cpp \
util/bytevectorhash.cpp \
$(BITCOIN_CORE_H)
if GLIBC_BACK_COMPAT
libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp
AM_LDFLAGS += $(COMPAT_LDFLAGS)
endif
# cli: shared between bitcoin-cli and bitcoin-qt
libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_cli_a_SOURCES = \
rpc/client.cpp \
$(BITCOIN_CORE_H)
# seeder library
libbitcoin_seeder_a_CPPFLAGS = $(AM_CPPFLAGS) $(PIE_FLAGS) $(BITCOIN_SEEDER_INCLUDES)
libbitcoin_seeder_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_seeder_a_SOURCES = \
seeder/bitcoin.cpp \
seeder/bitcoin.h \
seeder/db.cpp \
seeder/db.h \
seeder/dns.cpp \
seeder/dns.h \
seeder/util.h
nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h
#
# bitcoind binary #
bitcoind_SOURCES = bitcoind.cpp
bitcoind_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
bitcoind_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
if TARGET_WINDOWS
bitcoind_SOURCES += bitcoind-res.rc
endif
bitcoind_LDADD = \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_WALLET) \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_COMMON) \
$(LIBUNIVALUE) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_ZMQ) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_CRYPTO) \
$(LIBLEVELDB) \
$(LIBLEVELDB_SSE42) \
$(LIBMEMENV) \
$(LIBSECP256K1)
bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS)
# bitcoin-cli binary #
bitcoin_cli_SOURCES = bitcoin-cli.cpp
bitcoin_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS)
bitcoin_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
if TARGET_WINDOWS
bitcoin_cli_SOURCES += bitcoin-cli-res.rc
endif
bitcoin_cli_LDADD = \
$(LIBBITCOIN_CLI) \
$(LIBUNIVALUE) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO)
bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS)
#
# bitcoin-seeder binary #
bitcoin_seeder_SOURCES = seeder/main.cpp
bitcoin_seeder_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_SEEDER_INCLUDES)
bitcoin_seeder_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
bitcoin_seeder_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
bitcoin_seeder_LDADD = \
$(LIBBITCOIN_SEEDER) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBBITCOIN_CONSENSUS)
bitcoin_seeder_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
#
# bitcoin-tx binary #
bitcoin_tx_SOURCES = bitcoin-tx.cpp
bitcoin_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
bitcoin_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
if TARGET_WINDOWS
bitcoin_tx_SOURCES += bitcoin-tx-res.rc
endif
bitcoin_tx_LDADD = \
$(LIBUNIVALUE) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_CRYPTO) \
$(LIBSECP256K1)
bitcoin_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
#
# bitcoinconsensus library #
if BUILD_BITCOIN_LIBS
include_HEADERS = script/bitcoinconsensus.h
libbitcoinconsensus_la_SOURCES = $(crypto_libbitcoin_crypto_base_a_SOURCES) $(libbitcoin_consensus_a_SOURCES)
if GLIBC_BACK_COMPAT
libbitcoinconsensus_la_SOURCES += compat/glibc_compat.cpp
endif
libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS)
libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1)
libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL
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
CTAES_DIST += crypto/ctaes/README.md
CTAES_DIST += crypto/ctaes/test.c
CLEANFILES = $(EXTRA_LIBRARIES)
CLEANFILES += *.gcda *.gcno
CLEANFILES += compat/*.gcda compat/*.gcno
CLEANFILES += consensus/*.gcda consensus/*.gcno
CLEANFILES += crypto/*.gcda crypto/*.gcno
CLEANFILES += policy/*.gcda policy/*.gcno
CLEANFILES += primitives/*.gcda primitives/*.gcno
CLEANFILES += script/*.gcda script/*.gcno
CLEANFILES += support/*.gcda support/*.gcno
CLEANFILES += univalue/*.gcda univalue/*.gcno
CLEANFILES += wallet/*.gcda wallet/*.gcno
CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno
CLEANFILES += zmq/*.gcda zmq/*.gcno
CLEANFILES += obj/build.h
EXTRA_DIST = $(CTAES_DIST)
config/bitcoin-config.h: config/stamp-h1
@$(MAKE) -C $(top_builddir) $(subdir)/$(@)
config/stamp-h1: $(top_srcdir)/$(subdir)/config/bitcoin-config.h.in $(top_builddir)/config.status
$(AM_V_at)$(MAKE) -C $(top_builddir) $(subdir)/$(@)
$(top_srcdir)/$(subdir)/config/bitcoin-config.h.in: $(am__configure_deps)
$(AM_V_at)$(MAKE) -C $(top_srcdir) $(subdir)/config/bitcoin-config.h.in
clean-local:
-$(MAKE) -C secp256k1 clean
-$(MAKE) -C univalue clean
-rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno
-rm -rf test/__pycache__
.rc.o:
@test -f $(WINDRES)
## FIXME: How to get the appropriate modulename_CPPFLAGS in here?
$(AM_V_GEN) $(WINDRES) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) -DWINDRES_PREPROC -i $< -o $@
.mm.o:
$(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) -c -o $@ $<
check-symbols: $(bin_PROGRAMS)
if GLIBC_BACK_COMPAT
@echo "Checking glibc back compat..."
$(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py < $(bin_PROGRAMS)
endif
check-security: $(bin_PROGRAMS)
if HARDEN
@echo "Checking binary security..."
$(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS)
endif
if ENABLE_BIP70
%.pb.cc %.pb.h: %.proto
@test -f $(PROTOC)
$(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$( $@.log 2>&1 || (cat $@.log && false)
%.json.h: %.json
@$(MKDIR_P) $(@D)
@{ \
echo "namespace json_tests{" && \
echo "static unsigned const char $(*F)[] = {" && \
$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \
echo "};};"; \
} > "$@.new" && mv -f "$@.new" "$@"
@echo "Generated $@"
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 4fa77a13f1..6c3a8e4fc3 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -1,230 +1,233 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
+#include
#include
#include
const std::function G_TRANSLATION_FUN = nullptr;
/* Introduction text for doxygen: */
/*! \mainpage Developer documentation
*
* \section intro_sec Introduction
*
* This is the developer documentation of Bitcoin ABC
* (https://www.bitcoinabc.org/). Bitcoin ABC is a client for the digital
* currency called Bitcoin Cash (https://www.bitcoincash.org/), which enables
* instant payments to anyone, anywhere in the world. Bitcoin Cash uses
* peer-to-peer technology to operate with no central authority: managing
* transactions and issuing money are carried out collectively by the network.
*
* The software is a community-driven open source project, released under the
* MIT license.
*
* \section Navigation
* Use the buttons Namespaces
, Classes
or
* Files
at the top of the page to start navigating the code.
*/
static void WaitForShutdown() {
while (!ShutdownRequested()) {
MilliSleep(200);
}
Interrupt();
}
//////////////////////////////////////////////////////////////////////////////
//
// Start
//
static bool AppInit(int argc, char *argv[]) {
// FIXME: Ideally, we'd like to build the config here, but that's currently
// not possible as the whole application has too many global state. However,
// this is a first step.
auto &config = const_cast(GetConfig());
RPCServer rpcServer;
HTTPRPCRequestProcessor httpRPCRequestProcessor(config, rpcServer);
InitInterfaces interfaces;
interfaces.chain = interfaces::MakeChain();
bool fRet = false;
+ util::ThreadRename("init");
+
//
// Parameters
//
// If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's
// main()
SetupServerArgs();
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
fprintf(stderr, "Error parsing command line arguments: %s\n",
error.c_str());
return false;
}
// Process help and version before taking care about datadir
if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
std::string strUsage =
PACKAGE_NAME " Daemon version " + FormatFullVersion() + "\n";
if (gArgs.IsArgSet("-version")) {
strUsage += FormatParagraph(LicenseInfo());
} else {
strUsage += "\nUsage: bitcoind [options] "
"Start " PACKAGE_NAME " Daemon\n";
strUsage += "\n" + gArgs.GetHelpMessage();
}
fprintf(stdout, "%s", strUsage.c_str());
return true;
}
try {
if (!fs::is_directory(GetDataDir(false))) {
fprintf(stderr,
"Error: Specified data directory \"%s\" does not exist.\n",
gArgs.GetArg("-datadir", "").c_str());
return false;
}
if (!gArgs.ReadConfigFiles(error)) {
fprintf(stderr, "Error reading configuration file: %s\n",
error.c_str());
return false;
}
// Check for -testnet or -regtest parameter (Params() calls are only
// valid after this clause)
try {
SelectParams(gArgs.GetChainName());
} catch (const std::exception &e) {
fprintf(stderr, "Error: %s\n", e.what());
return false;
}
// Make sure we create the net-specific data directory early on: if it
// is new, this has a side effect of also creating
// //wallets/.
//
// TODO: this should be removed once GetDataDir() no longer creates the
// wallets/ subdirectory.
// See more info at:
// https://reviews.bitcoinabc.org/D3312
GetDataDir(true);
// Error out when loose non-argument tokens are encountered on command
// line
for (int i = 1; i < argc; i++) {
if (!IsSwitchChar(argv[i][0])) {
fprintf(stderr,
"Error: Command line contains unexpected token '%s', "
"see bitcoind -h for a list of options.\n",
argv[i]);
return false;
}
}
// -server defaults to true for bitcoind but not for the GUI so do this
// here
gArgs.SoftSetBoolArg("-server", true);
// Set this early so that parameter interactions go to console
InitLogging();
InitParameterInteraction();
if (!AppInitBasicSetup()) {
// InitError will have been called with detailed error, which ends
// up on console
return false;
}
if (!AppInitParameterInteraction(config)) {
// InitError will have been called with detailed error, which ends
// up on console
return false;
}
if (!AppInitSanityChecks()) {
// InitError will have been called with detailed error, which ends
// up on console
return false;
}
if (gArgs.GetBoolArg("-daemon", false)) {
#if HAVE_DECL_DAEMON
#if defined(MAC_OSX)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
fprintf(stdout, "Bitcoin server starting\n");
// Daemonize
if (daemon(1, 0)) {
// don't chdir (1), do close FDs (0)
fprintf(stderr, "Error: daemon() failed: %s\n",
strerror(errno));
return false;
}
#if defined(MAC_OSX)
#pragma GCC diagnostic pop
#endif
#else
fprintf(
stderr,
"Error: -daemon is not supported on this operating system\n");
return false;
#endif // HAVE_DECL_DAEMON
}
// Lock data directory after daemonization
if (!AppInitLockDataDirectory()) {
// If locking the data directory failed, exit immediately
return false;
}
fRet =
AppInitMain(config, rpcServer, httpRPCRequestProcessor, interfaces);
} catch (const std::exception &e) {
PrintExceptionContinue(&e, "AppInit()");
} catch (...) {
PrintExceptionContinue(nullptr, "AppInit()");
}
if (!fRet) {
Interrupt();
} else {
WaitForShutdown();
}
Shutdown(interfaces);
return fRet;
}
int main(int argc, char *argv[]) {
#ifdef WIN32
util::WinCmdLineArgs winArgs;
std::tie(argc, argv) = winArgs.get();
#endif
SetupEnvironment();
// Connect bitcoind signal handlers
noui_connect();
return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
}
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 6ae9b19887..64895005c7 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -1,687 +1,688 @@
// Copyright (c) 2015-2016 The Bitcoin Core developers
// Copyright (c) 2018-2019 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include
#include
#include
#include
#include
#include
#include // For HTTP status codes
#include
#include
#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
#ifdef EVENT__HAVE_NETINET_IN_H
#include
#ifdef _XOPEN_SOURCE_EXTENDED
#include
#endif
#endif
#include
#include
#include
#include
#include
#include
#include
#include
/** Maximum size of http request (request line + headers) */
static const size_t MAX_HEADERS_SIZE = 8192;
/**
* Maximum HTTP post body size. Twice the maximum block size is added to this
* value in practice.
*/
static const size_t MIN_SUPPORTED_BODY_SIZE = 0x02000000;
/** HTTP request work item */
class HTTPWorkItem final : public HTTPClosure {
public:
HTTPWorkItem(Config &_config, std::unique_ptr _req,
const std::string &_path, const HTTPRequestHandler &_func)
: req(std::move(_req)), path(_path), func(_func), config(&_config) {}
void operator()() override { func(*config, req.get(), path); }
std::unique_ptr req;
private:
std::string path;
HTTPRequestHandler func;
Config *config;
};
/**
* Simple work queue for distributing work over multiple threads.
* Work items are simply callable objects.
*/
template class WorkQueue {
private:
/** Mutex protects entire object */
Mutex cs;
std::condition_variable cond;
std::deque> queue;
bool running;
size_t maxDepth;
public:
explicit WorkQueue(size_t _maxDepth) : running(true), maxDepth(_maxDepth) {}
/**
* Precondition: worker threads have all stopped (they have all been joined)
*/
~WorkQueue() {}
/** Enqueue a work item */
bool Enqueue(WorkItem *item) {
LOCK(cs);
if (queue.size() >= maxDepth) {
return false;
}
queue.emplace_back(std::unique_ptr(item));
cond.notify_one();
return true;
}
/** Thread function */
void Run() {
while (true) {
std::unique_ptr i;
{
WAIT_LOCK(cs, lock);
while (running && queue.empty()) {
cond.wait(lock);
}
if (!running) {
break;
}
i = std::move(queue.front());
queue.pop_front();
}
(*i)();
}
}
/** Interrupt and exit loops */
void Interrupt() {
LOCK(cs);
running = false;
cond.notify_all();
}
};
struct HTTPPathHandler {
HTTPPathHandler(std::string _prefix, bool _exactMatch,
HTTPRequestHandler _handler)
: prefix(_prefix), exactMatch(_exactMatch), handler(_handler) {}
std::string prefix;
bool exactMatch;
HTTPRequestHandler handler;
};
/** HTTP module state */
//! libevent event loop
static struct event_base *eventBase = nullptr;
//! HTTP server
struct evhttp *eventHTTP = nullptr;
//! List of subnets to allow RPC connections from
static std::vector rpc_allow_subnets;
//! Work queue for handling longer requests off the event loop thread
static WorkQueue *workQueue = nullptr;
//! Handlers for (sub)paths
std::vector pathHandlers;
//! Bound listening sockets
std::vector boundSockets;
/** Check if a network address is allowed to access the HTTP server */
static bool ClientAllowed(const CNetAddr &netaddr) {
if (!netaddr.IsValid()) {
return false;
}
for (const CSubNet &subnet : rpc_allow_subnets) {
if (subnet.Match(netaddr)) {
return true;
}
}
return false;
}
/** Initialize ACL list for HTTP server */
static bool InitHTTPAllowList() {
rpc_allow_subnets.clear();
CNetAddr localv4;
CNetAddr localv6;
LookupHost("127.0.0.1", localv4, false);
LookupHost("::1", localv6, false);
// always allow IPv4 local subnet.
rpc_allow_subnets.push_back(CSubNet(localv4, 8));
// always allow IPv6 localhost.
rpc_allow_subnets.push_back(CSubNet(localv6));
for (const std::string &strAllow : gArgs.GetArgs("-rpcallowip")) {
CSubNet subnet;
LookupSubNet(strAllow.c_str(), subnet);
if (!subnet.IsValid()) {
uiInterface.ThreadSafeMessageBox(
strprintf("Invalid -rpcallowip subnet specification: %s. "
"Valid are a single IP (e.g. 1.2.3.4), a "
"network/netmask (e.g. 1.2.3.4/255.255.255.0) or a "
"network/CIDR (e.g. 1.2.3.4/24).",
strAllow),
"", CClientUIInterface::MSG_ERROR);
return false;
}
rpc_allow_subnets.push_back(subnet);
}
std::string strAllowed;
for (const CSubNet &subnet : rpc_allow_subnets) {
strAllowed += subnet.ToString() + " ";
}
LogPrint(BCLog::HTTP, "Allowing HTTP connections from: %s\n", strAllowed);
return true;
}
/** HTTP request method as string - use for logging only */
static std::string RequestMethodString(HTTPRequest::RequestMethod m) {
switch (m) {
case HTTPRequest::GET:
return "GET";
case HTTPRequest::POST:
return "POST";
case HTTPRequest::HEAD:
return "HEAD";
case HTTPRequest::PUT:
return "PUT";
case HTTPRequest::OPTIONS:
return "OPTIONS";
default:
return "unknown";
}
}
/** HTTP request callback */
static void http_request_cb(struct evhttp_request *req, void *arg) {
Config &config = *reinterpret_cast(arg);
// Disable reading to work around a libevent bug, fixed in 2.2.0.
if (event_get_version_number() >= 0x02010600 &&
event_get_version_number() < 0x02020001) {
evhttp_connection *conn = evhttp_request_get_connection(req);
if (conn) {
bufferevent *bev = evhttp_connection_get_bufferevent(conn);
if (bev) {
bufferevent_disable(bev, EV_READ);
}
}
}
auto hreq = std::make_unique(req);
LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n",
RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(),
hreq->GetPeer().ToString());
// Early address-based allow check
if (!ClientAllowed(hreq->GetPeer())) {
hreq->WriteReply(HTTP_FORBIDDEN);
return;
}
// Early reject unknown HTTP methods
if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) {
hreq->WriteReply(HTTP_BADMETHOD);
return;
}
// Find registered handler for prefix
std::string strURI = hreq->GetURI();
std::string path;
std::vector::const_iterator i = pathHandlers.begin();
std::vector::const_iterator iend = pathHandlers.end();
for (; i != iend; ++i) {
bool match = false;
if (i->exactMatch) {
match = (strURI == i->prefix);
} else {
match = (strURI.substr(0, i->prefix.size()) == i->prefix);
}
if (match) {
path = strURI.substr(i->prefix.size());
break;
}
}
// Dispatch to worker thread.
if (i != iend) {
std::unique_ptr item(
new HTTPWorkItem(config, std::move(hreq), path, i->handler));
assert(workQueue);
if (workQueue->Enqueue(item.get())) {
/* if true, queue took ownership */
item.release();
} else {
LogPrintf("WARNING: request rejected because http work queue depth "
"exceeded, it can be increased with the -rpcworkqueue= "
"setting\n");
item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded");
}
} else {
hreq->WriteReply(HTTP_NOTFOUND);
}
}
/** Callback to reject HTTP requests after shutdown. */
static void http_reject_request_cb(struct evhttp_request *req, void *) {
LogPrint(BCLog::HTTP, "Rejecting request while shutting down\n");
evhttp_send_error(req, HTTP_SERVUNAVAIL, nullptr);
}
/** Event dispatcher thread */
static bool ThreadHTTP(struct event_base *base) {
- RenameThread("bitcoin-http");
+ util::ThreadRename("http");
LogPrint(BCLog::HTTP, "Entering http event loop\n");
event_base_dispatch(base);
// Event loop will be interrupted by InterruptHTTPServer()
LogPrint(BCLog::HTTP, "Exited http event loop\n");
return event_base_got_break(base) == 0;
}
/** Bind HTTP server to specified addresses */
static bool HTTPBindAddresses(struct evhttp *http) {
int defaultPort = gArgs.GetArg("-rpcport", BaseParams().RPCPort());
std::vector> endpoints;
// Determine what addresses to bind to
if (!gArgs.IsArgSet("-rpcallowip")) {
// Default to loopback if not allowing external IPs.
endpoints.push_back(std::make_pair("::1", defaultPort));
endpoints.push_back(std::make_pair("127.0.0.1", defaultPort));
if (gArgs.IsArgSet("-rpcbind")) {
LogPrintf("WARNING: option -rpcbind was ignored because "
"-rpcallowip was not specified, refusing to allow "
"everyone to connect\n");
}
} else if (gArgs.IsArgSet("-rpcbind")) {
// Specific bind address.
for (const std::string &strRPCBind : gArgs.GetArgs("-rpcbind")) {
int port = defaultPort;
std::string host;
SplitHostPort(strRPCBind, port, host);
endpoints.push_back(std::make_pair(host, port));
}
} else {
// No specific bind address specified, bind to any.
endpoints.push_back(std::make_pair("::", defaultPort));
endpoints.push_back(std::make_pair("0.0.0.0", defaultPort));
}
// Bind addresses
for (std::vector>::iterator i =
endpoints.begin();
i != endpoints.end(); ++i) {
LogPrint(BCLog::HTTP, "Binding RPC on address %s port %i\n", i->first,
i->second);
evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(
http, i->first.empty() ? nullptr : i->first.c_str(), i->second);
if (bind_handle) {
boundSockets.push_back(bind_handle);
} else {
LogPrintf("Binding RPC on address %s port %i failed.\n", i->first,
i->second);
}
}
return !boundSockets.empty();
}
/** Simple wrapper to set thread name and run work queue */
-static void HTTPWorkQueueRun(WorkQueue *queue) {
- RenameThread("bitcoin-httpworker");
+static void HTTPWorkQueueRun(WorkQueue *queue, int worker_num) {
+ util::ThreadRename(strprintf("httpworker.%i", worker_num));
queue->Run();
}
/** libevent event log callback */
static void libevent_log_cb(int severity, const char *msg) {
#ifndef EVENT_LOG_WARN
// EVENT_LOG_WARN was added in 2.0.19; but before then _EVENT_LOG_WARN existed.
#define EVENT_LOG_WARN _EVENT_LOG_WARN
#endif
// Log warn messages and higher without debug category.
if (severity >= EVENT_LOG_WARN) {
LogPrintf("libevent: %s\n", msg);
} else {
LogPrint(BCLog::LIBEVENT, "libevent: %s\n", msg);
}
}
bool InitHTTPServer(Config &config) {
if (!InitHTTPAllowList()) {
return false;
}
if (gArgs.GetBoolArg("-rpcssl", false)) {
uiInterface.ThreadSafeMessageBox(
"SSL mode for RPC (-rpcssl) is no longer supported.", "",
CClientUIInterface::MSG_ERROR);
return false;
}
// Redirect libevent's logging to our own log
event_set_log_callback(&libevent_log_cb);
// Update libevent's log handling. Returns false if our version of
// libevent doesn't support debug logging, in which case we should
// clear the BCLog::LIBEVENT flag.
if (!UpdateHTTPServerLogging(
LogInstance().WillLogCategory(BCLog::LIBEVENT))) {
LogInstance().DisableCategory(BCLog::LIBEVENT);
}
#ifdef WIN32
evthread_use_windows_threads();
#else
evthread_use_pthreads();
#endif
raii_event_base base_ctr = obtain_event_base();
/* Create a new evhttp object to handle requests. */
raii_evhttp http_ctr = obtain_evhttp(base_ctr.get());
struct evhttp *http = http_ctr.get();
if (!http) {
LogPrintf("couldn't create evhttp. Exiting.\n");
return false;
}
evhttp_set_timeout(
http, gArgs.GetArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT));
evhttp_set_max_headers_size(http, MAX_HEADERS_SIZE);
evhttp_set_max_body_size(http, MIN_SUPPORTED_BODY_SIZE +
2 * config.GetMaxBlockSize());
evhttp_set_gencb(http, http_request_cb, &config);
// Only POST and OPTIONS are supported, but we return HTTP 405 for the
// others
evhttp_set_allowed_methods(
http, EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_HEAD |
EVHTTP_REQ_PUT | EVHTTP_REQ_DELETE | EVHTTP_REQ_OPTIONS);
if (!HTTPBindAddresses(http)) {
LogPrintf("Unable to bind any endpoint for RPC server\n");
return false;
}
LogPrint(BCLog::HTTP, "Initialized HTTP server\n");
int workQueueDepth = std::max(
(long)gArgs.GetArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
LogPrintf("HTTP: creating work queue of depth %d\n", workQueueDepth);
workQueue = new WorkQueue(workQueueDepth);
// transfer ownership to eventBase/HTTP via .release()
eventBase = base_ctr.release();
eventHTTP = http_ctr.release();
return true;
}
bool UpdateHTTPServerLogging(bool enable) {
#if LIBEVENT_VERSION_NUMBER >= 0x02010100
if (enable) {
event_enable_debug_logging(EVENT_DBG_ALL);
} else {
event_enable_debug_logging(EVENT_DBG_NONE);
}
return true;
#else
// Can't update libevent logging if version < 02010100
return false;
#endif
}
std::thread threadHTTP;
static std::vector g_thread_http_workers;
void StartHTTPServer() {
LogPrint(BCLog::HTTP, "Starting HTTP server\n");
int rpcThreads =
std::max((long)gArgs.GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
threadHTTP = std::thread(ThreadHTTP, eventBase);
for (int i = 0; i < rpcThreads; i++) {
- g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue);
+ g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue, i);
}
}
void InterruptHTTPServer() {
LogPrint(BCLog::HTTP, "Interrupting HTTP server\n");
if (eventHTTP) {
// Reject requests on current connections
evhttp_set_gencb(eventHTTP, http_reject_request_cb, nullptr);
}
if (workQueue) {
workQueue->Interrupt();
}
}
void StopHTTPServer() {
LogPrint(BCLog::HTTP, "Stopping HTTP server\n");
if (workQueue) {
LogPrint(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n");
for (auto &thread : g_thread_http_workers) {
thread.join();
}
g_thread_http_workers.clear();
delete workQueue;
workQueue = nullptr;
}
// Unlisten sockets, these are what make the event loop running, which means
// that after this and all connections are closed the event loop will quit.
for (evhttp_bound_socket *socket : boundSockets) {
evhttp_del_accept_socket(eventHTTP, socket);
}
boundSockets.clear();
if (eventBase) {
LogPrint(BCLog::HTTP, "Waiting for HTTP event thread to exit\n");
threadHTTP.join();
}
if (eventHTTP) {
evhttp_free(eventHTTP);
eventHTTP = nullptr;
}
if (eventBase) {
event_base_free(eventBase);
eventBase = nullptr;
}
LogPrint(BCLog::HTTP, "Stopped HTTP server\n");
}
struct event_base *EventBase() {
return eventBase;
}
static void httpevent_callback_fn(evutil_socket_t, short, void *data) {
// Static handler: simply call inner handler
HTTPEvent *self = static_cast(data);
self->handler();
if (self->deleteWhenTriggered) {
delete self;
}
}
HTTPEvent::HTTPEvent(struct event_base *base, bool _deleteWhenTriggered,
const std::function &_handler)
: deleteWhenTriggered(_deleteWhenTriggered), handler(_handler) {
ev = event_new(base, -1, 0, httpevent_callback_fn, this);
assert(ev);
}
HTTPEvent::~HTTPEvent() {
event_free(ev);
}
void HTTPEvent::trigger(struct timeval *tv) {
if (tv == nullptr) {
// Immediately trigger event in main thread.
event_active(ev, 0, 0);
} else {
// Trigger after timeval passed.
evtimer_add(ev, tv);
}
}
HTTPRequest::HTTPRequest(struct evhttp_request *_req)
: req(_req), replySent(false) {}
HTTPRequest::~HTTPRequest() {
if (!replySent) {
// Keep track of whether reply was sent to avoid request leaks
LogPrintf("%s: Unhandled request\n", __func__);
WriteReply(HTTP_INTERNAL, "Unhandled request");
}
// evhttpd cleans up the request, as long as a reply was sent.
}
std::pair
HTTPRequest::GetHeader(const std::string &hdr) const {
const struct evkeyvalq *headers = evhttp_request_get_input_headers(req);
assert(headers);
const char *val = evhttp_find_header(headers, hdr.c_str());
if (val) {
return std::make_pair(true, val);
} else {
return std::make_pair(false, "");
}
}
std::string HTTPRequest::ReadBody() {
struct evbuffer *buf = evhttp_request_get_input_buffer(req);
if (!buf) {
return "";
}
size_t size = evbuffer_get_length(buf);
/**
* Trivial implementation: if this is ever a performance bottleneck,
* internal copying can be avoided in multi-segment buffers by using
* evbuffer_peek and an awkward loop. Though in that case, it'd be even
* better to not copy into an intermediate string but use a stream
* abstraction to consume the evbuffer on the fly in the parsing algorithm.
*/
const char *data = (const char *)evbuffer_pullup(buf, size);
// returns nullptr in case of empty buffer.
if (!data) {
return "";
}
std::string rv(data, size);
evbuffer_drain(buf, size);
return rv;
}
void HTTPRequest::WriteHeader(const std::string &hdr,
const std::string &value) {
struct evkeyvalq *headers = evhttp_request_get_output_headers(req);
assert(headers);
evhttp_add_header(headers, hdr.c_str(), value.c_str());
}
/**
* Closure sent to main thread to request a reply to be sent to a HTTP request.
* Replies must be sent in the main loop in the main http thread, this cannot be
* done from worker threads.
*/
void HTTPRequest::WriteReply(int nStatus, const std::string &strReply) {
assert(!replySent && req);
if (ShutdownRequested()) {
WriteHeader("Connection", "close");
}
// Send event to main http thread to send reply message
struct evbuffer *evb = evhttp_request_get_output_buffer(req);
assert(evb);
evbuffer_add(evb, strReply.data(), strReply.size());
auto req_copy = req;
HTTPEvent *ev = new HTTPEvent(eventBase, true, [req_copy, nStatus] {
evhttp_send_reply(req_copy, nStatus, nullptr, nullptr);
// Re-enable reading from the socket. This is the second part of the
// libevent workaround above.
if (event_get_version_number() >= 0x02010600 &&
event_get_version_number() < 0x02020001) {
evhttp_connection *conn = evhttp_request_get_connection(req_copy);
if (conn) {
bufferevent *bev = evhttp_connection_get_bufferevent(conn);
if (bev) {
bufferevent_enable(bev, EV_READ | EV_WRITE);
}
}
}
});
ev->trigger(nullptr);
replySent = true;
// transferred back to main thread.
req = nullptr;
}
CService HTTPRequest::GetPeer() const {
evhttp_connection *con = evhttp_request_get_connection(req);
CService peer;
if (con) {
// evhttp retains ownership over returned address string
const char *address = "";
uint16_t port = 0;
evhttp_connection_get_peer(con, (char **)&address, &port);
peer = LookupNumeric(address, port);
}
return peer;
}
std::string HTTPRequest::GetURI() const {
return evhttp_request_get_uri(req);
}
HTTPRequest::RequestMethod HTTPRequest::GetRequestMethod() const {
switch (evhttp_request_get_command(req)) {
case EVHTTP_REQ_GET:
return GET;
case EVHTTP_REQ_POST:
return POST;
case EVHTTP_REQ_HEAD:
return HEAD;
case EVHTTP_REQ_PUT:
return PUT;
case EVHTTP_REQ_OPTIONS:
return OPTIONS;
default:
return UNKNOWN;
}
}
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch,
const HTTPRequestHandler &handler) {
LogPrint(BCLog::HTTP, "Registering HTTP handler for %s (exactmatch %d)\n",
prefix, exactMatch);
pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, handler));
}
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch) {
std::vector::iterator i = pathHandlers.begin();
std::vector::iterator iend = pathHandlers.end();
for (; i != iend; ++i) {
if (i->prefix == prefix && i->exactMatch == exactMatch) {
break;
}
}
if (i != iend) {
LogPrint(BCLog::HTTP,
"Unregistering HTTP handler for %s (exactmatch %d)\n", prefix,
exactMatch);
pathHandlers.erase(i);
}
}
diff --git a/src/init.cpp b/src/init.cpp
index 3baaf8fd08..18f6243b0b 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1,2538 +1,2547 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include