diff --git a/contrib/devtools/check-deps.sh b/contrib/devtools/check-deps.sh new file mode 100755 index 00000000000..9d2eebe14d8 --- /dev/null +++ b/contrib/devtools/check-deps.sh @@ -0,0 +1,203 @@ +#!/usr/bin/env bash + +export LC_ALL=C +set -Eeuo pipefail + +# Declare paths to libraries +declare -A LIBS +LIBS[cli]="libbitcoin_cli.a" +LIBS[common]="libbitcoin_common.a" +LIBS[consensus]="libbitcoin_consensus.a" +LIBS[crypto]="crypto/.libs/libbitcoin_crypto_base.a crypto/.libs/libbitcoin_crypto_x86_shani.a crypto/.libs/libbitcoin_crypto_sse41.a crypto/.libs/libbitcoin_crypto_avx2.a" +LIBS[node]="libbitcoin_node.a" +LIBS[util]="libbitcoin_util.a" +LIBS[wallet]="libbitcoin_wallet.a" +LIBS[wallet_tool]="libbitcoin_wallet_tool.a" + +# Declare allowed dependencies "X Y" where X is allowed to depend on Y. This +# list is taken from doc/design/libraries.md. +ALLOWED_DEPENDENCIES=( + "cli common" + "cli util" + "common consensus" + "common crypto" + "common util" + "consensus crypto" + "node common" + "node consensus" + "node crypto" + "node kernel" + "node util" + "util crypto" + "wallet common" + "wallet crypto" + "wallet util" + "wallet_tool util" + "wallet_tool wallet" +) + +# Add minor dependencies omitted from doc/design/libraries.md to keep the +# dependency diagram simple. +ALLOWED_DEPENDENCIES+=( + "wallet consensus" + "wallet_tool common" + "wallet_tool crypto" +) + +# Declare list of known errors that should be suppressed. +declare -A SUPPRESS +# init.cpp file currently calls Berkeley DB sanity check function on startup, so +# there is an undocumented dependency of the node library on the wallet library. +SUPPRESS["libbitcoin_node_a-init.o libbitcoin_wallet_a-bdb.o _ZN6wallet27BerkeleyDatabaseSanityCheckEv"]=1 +# init/common.cpp file calls InitError and InitWarning from interface_ui which +# is currently part of the node library. interface_ui should just be part of the +# common library instead, and is moved in +# https://github.com/bitcoin/bitcoin/issues/10102 +SUPPRESS["libbitcoin_common_a-common.o libbitcoin_node_a-interface_ui.o _Z11InitWarningRK13bilingual_str"]=1 +SUPPRESS["libbitcoin_common_a-common.o libbitcoin_node_a-interface_ui.o _Z9InitErrorRK13bilingual_str"]=1 +# rpc/external_signer.cpp adds defines node RPC methods but is built as part of the +# common library. It should be moved to the node library instead. +SUPPRESS["libbitcoin_common_a-external_signer.o libbitcoin_node_a-server.o _ZN9CRPCTable13appendCommandERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPK11CRPCCommand"]=1 + +usage() { + echo "Usage: $(basename "${BASH_SOURCE[0]}") [BUILD_DIR]" +} + +# Output makefile targets, converting library .a paths to libtool .la targets +lib_targets() { + for lib in "${!LIBS[@]}"; do + for lib_path in ${LIBS[$lib]}; do + # shellcheck disable=SC2001 + sed 's:/.libs/\(.*\)\.a$:/\1.la:g' <<<"$lib_path" + done + done +} + +# Extract symbol names and object names and write to text files +extract_symbols() { + local temp_dir="$1" + for lib in "${!LIBS[@]}"; do + for lib_path in ${LIBS[$lib]}; do + nm -o "$lib_path" | grep ' T ' | awk '{print $3, $1}' >> "${temp_dir}/${lib}_exports.txt" + nm -o "$lib_path" | grep ' U ' | awk '{print $3, $1}' >> "${temp_dir}/${lib}_imports.txt" + awk '{print $1}' "${temp_dir}/${lib}_exports.txt" | sort -u > "${temp_dir}/${lib}_exported_symbols.txt" + awk '{print $1}' "${temp_dir}/${lib}_imports.txt" | sort -u > "${temp_dir}/${lib}_imported_symbols.txt" + done + done +} + +# Lookup object name(s) corresponding to symbol name in text file +obj_names() { + local symbol="$1" + local txt_file="$2" + sed -n "s/^$symbol [^:]\\+:\\([^:]\\+\\):[^:]*\$/\\1/p" "$txt_file" | sort -u +} + +# Iterate through libraries and find disallowed dependencies +check_libraries() { + local temp_dir="$1" + local result=0 + for src in "${!LIBS[@]}"; do + for dst in "${!LIBS[@]}"; do + if [ "$src" != "$dst" ] && ! is_allowed "$src" "$dst"; then + if ! check_disallowed "$src" "$dst" "$temp_dir"; then + result=1 + fi + fi + done + done + check_not_suppressed + return $result +} + +# Return whether src library is allowed to depend on dst. +is_allowed() { + local src="$1" + local dst="$2" + for allowed in "${ALLOWED_DEPENDENCIES[@]}"; do + if [ "$src $dst" = "$allowed" ]; then + return 0 + fi + done + return 1 +} + +# Return whether src library imports any symbols from dst, assuming src is not +# allowed to depend on dst. +check_disallowed() { + local src="$1" + local dst="$2" + local temp_dir="$3" + local result=0 + + # Loop over symbol names exported by dst and imported by src + while read symbol; do + local dst_obj + dst_obj=$(obj_names "$symbol" "${temp_dir}/${dst}_exports.txt") + while read src_obj; do + if ! check_suppress "$src_obj" "$dst_obj" "$symbol"; then + echo "Error: $src_obj depends on $dst_obj symbol '$(c++filt "$symbol")', can suppess with:" + echo " SUPPRESS[\"$src_obj $dst_obj $symbol\"]=1" + result=1 + fi + done < <(obj_names "$symbol" "${temp_dir}/${src}_imports.txt") + done < <(comm -12 "${temp_dir}/${dst}_exported_symbols.txt" "${temp_dir}/${src}_imported_symbols.txt") + return $result +} + +# Declare array to track errors which were suppressed. +declare -A SUPPRESSED + +# Return whether error should be suppressed and record suppresssion in +# SUPPRESSED array. +check_suppress() { + local src_obj="$1" + local dst_obj="$2" + local symbol="$3" + for suppress in "${!SUPPRESS[@]}"; do + read suppress_src suppress_dst suppress_pattern <<<"$suppress" + if [[ "$src_obj" == "$suppress_src" && "$dst_obj" == "$suppress_dst" && "$symbol" =~ $suppress_pattern ]]; then + SUPPRESSED["$suppress"]=1 + return 0 + fi + done + return 1 +} + +# Warn about error which were supposed to be suppress, but were not encountered. +check_not_suppressed() { + for suppress in "${!SUPPRESS[@]}"; do + if [[ ! -v SUPPRESSED[$suppress] ]]; then + echo >&2 "Warning: suppression '$suppress' was ignored, consider deleting." + fi + done +} + +# Check arguments. +if [ "$#" = 0 ]; then + BUILD_DIR="$(dirname "${BASH_SOURCE[0]}")/../../src" +elif [ "$#" = 1 ]; then + BUILD_DIR="$1" +else + echo >&2 "Error: wrong number of arguments." + usage >&2 + exit 1 +fi +if [ ! -f "$BUILD_DIR/Makefile" ]; then + echo >&2 "Error: directory '$BUILD_DIR' does not contain a makefile, please specify path to build directory for library targets." + usage >&2 + exit 1 +fi + +# Build libraries and run checks. +cd "$BUILD_DIR" +# shellcheck disable=SC2046 +make -j"$(nproc)" $(lib_targets) +TEMP_DIR="$(mktemp -d)" +extract_symbols "$TEMP_DIR" +if check_libraries "$TEMP_DIR"; then + echo "Success! No unexpected dependencies were detected." +else + echo >&2 "Error: Unexpected dependencies were detected. Check previous output." +fi +rm -r "$TEMP_DIR" diff --git a/doc/design/libraries.md b/doc/design/libraries.md index 251c52199d0..aa8034ab37b 100644 --- a/doc/design/libraries.md +++ b/doc/design/libraries.md @@ -5,6 +5,7 @@ | *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_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_ipc* | IPC functionality used by *bitcoin-node*, *bitcoin-wallet*, *bitcoin-gui* executables to communicate when [`--enable-multiprocess`](multiprocess.md) is used. | @@ -53,13 +54,18 @@ bitcoin-wallet[bitcoin-wallet]-->libbitcoin_wallet_tool; libbitcoin_cli-->libbitcoin_util; libbitcoin_cli-->libbitcoin_common; +libbitcoin_consensus-->libbitcoin_crypto; + libbitcoin_common-->libbitcoin_consensus; +libbitcoin_common-->libbitcoin_crypto; libbitcoin_common-->libbitcoin_util; libbitcoin_kernel-->libbitcoin_consensus; +libbitcoin_kernel-->libbitcoin_crypto; libbitcoin_kernel-->libbitcoin_util; libbitcoin_node-->libbitcoin_consensus; +libbitcoin_node-->libbitcoin_crypto; libbitcoin_node-->libbitcoin_kernel; libbitcoin_node-->libbitcoin_common; libbitcoin_node-->libbitcoin_util; @@ -67,7 +73,10 @@ libbitcoin_node-->libbitcoin_util; libbitcoinqt-->libbitcoin_common; libbitcoinqt-->libbitcoin_util; +libbitcoin_util-->libbitcoin_crypto; + libbitcoin_wallet-->libbitcoin_common; +libbitcoin_wallet-->libbitcoin_crypto; libbitcoin_wallet-->libbitcoin_util; libbitcoin_wallet_tool-->libbitcoin_wallet; @@ -78,22 +87,23 @@ class bitcoin-qt,bitcoind,bitcoin-cli,bitcoin-wallet bold ``` -**Dependency graph**. Arrows show linker symbol dependencies. *Consensus* lib depends on nothing. *Util* lib is depended on by everything. *Kernel* lib depends only on consensus and util. +**Dependency graph**. Arrows show linker symbol dependencies. *Crypto* lib depends on nothing. *Util* lib is depended on by everything. *Kernel* lib depends only on consensus, crypto, and util. - The graph shows what _linker symbols_ (functions and variables) from each library other libraries can call and reference directly, but it is not a call graph. For example, there is no arrow connecting *libbitcoin_wallet* and *libbitcoin_node* libraries, because these libraries are intended to be modular and not depend on each other's internal implementation details. But wallet code is still able to call node code indirectly through the `interfaces::Chain` abstract class in [`interfaces/chain.h`](../../src/interfaces/chain.h) and node code calls wallet code through the `interfaces::ChainClient` and `interfaces::Chain::Notifications` abstract classes in the same file. In general, defining abstract classes in [`src/interfaces/`](../../src/interfaces/) can be a convenient way of avoiding unwanted direct dependencies or circular dependencies between libraries. -- *libbitcoin_consensus* should be a standalone dependency that any library can depend on, and it should not depend on any other libraries itself. +- *libbitcoin_crypto* should be a standalone dependency that any library can depend on, and it should not depend on any other libraries itself. -- *libbitcoin_util* should also be a standalone dependency that any library can depend on, and it should not depend on other internal libraries. +- *libbitcoin_consensus* should only depend on *libbitcoin_crypto*, and all other libraries besides *libbitcoin_crypto* should be allowed to depend on it. -- *libbitcoin_common* should serve a similar function as *libbitcoin_util* and be a place for miscellaneous code used by various daemon, GUI, and CLI applications and libraries to live. It should not depend on anything other than *libbitcoin_util* and *libbitcoin_consensus*. The boundary between _util_ and _common_ is a little fuzzy but historically _util_ has been used for more generic, lower-level things like parsing hex, and _common_ has been used for bitcoin-specific, higher-level things like parsing base58. The difference between util and common is mostly important because *libbitcoin_kernel* is not supposed to depend on *libbitcoin_common*, only *libbitcoin_util*. In general, if it is ever unclear whether it is better to add code to *util* or *common*, it is probably better to add it to *common* unless it is very generically useful or useful particularly to include in the kernel. +- *libbitcoin_util* should be a standalone dependency that any library can depend on, and it should not depend on other libraries except *libbitcoin_crypto*. It provides basic utilities that fill in gaps in the C++ standard library and provide lightweight abstractions over platform-specific features. Since the util library is distributed with the kernel and is usable by kernel applications, it shouldn't contain functions that external code shouldn't call, like higher level code targetted at the node or wallet. (*libbitcoin_common* is a better place for higher level code, or code that is meant to be used by internal applications only.) +- *libbitcoin_common* is a home for miscellaneous shared code used by different Bitcoin Core applications. It should not depend on anything other than *libbitcoin_util*, *libbitcoin_consensus*, and *libbitcoin_crypto*. -- *libbitcoin_kernel* should only depend on *libbitcoin_util* and *libbitcoin_consensus*. +- *libbitcoin_kernel* should only depend on *libbitcoin_util*, *libbitcoin_consensus*, and *libbitcoin_crypto*. -- The only thing that should depend on *libbitcoin_kernel* internally should be *libbitcoin_node*. GUI and wallet libraries *libbitcoinqt* and *libbitcoin_wallet* in particular should not depend on *libbitcoin_kernel* and the unneeded functionality it would pull in, like block validation. To the extent that GUI and wallet code need scripting and signing functionality, they should be get able it from *libbitcoin_consensus*, *libbitcoin_common*, and *libbitcoin_util*, instead of *libbitcoin_kernel*. +- The only thing that should depend on *libbitcoin_kernel* internally should be *libbitcoin_node*. GUI and wallet libraries *libbitcoinqt* and *libbitcoin_wallet* in particular should not depend on *libbitcoin_kernel* and the unneeded functionality it would pull in, like block validation. To the extent that GUI and wallet code need scripting and signing functionality, they should be get able it from *libbitcoin_consensus*, *libbitcoin_common*, *libbitcoin_crypto*, and *libbitcoin_util*, instead of *libbitcoin_kernel*. - GUI, node, and wallet code internal implementations should all be independent of each other, and the *libbitcoinqt*, *libbitcoin_node*, *libbitcoin_wallet* libraries should never reference each other's symbols. They should only call each other through [`src/interfaces/`](../../src/interfaces/) abstract interfaces. diff --git a/src/Makefile.am b/src/Makefile.am index a69daeae2d4..2562c4cc655 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -137,13 +137,16 @@ BITCOIN_CORE_H = \ common/bloom.h \ common/init.h \ common/run_command.h \ + common/types.h \ common/url.h \ compat/assumptions.h \ compat/byteswap.h \ compat/compat.h \ compat/cpuid.h \ compat/endian.h \ + common/messages.h \ common/settings.h \ + common/signmessage.h \ common/system.h \ compressor.h \ consensus/consensus.h \ @@ -233,6 +236,7 @@ BITCOIN_CORE_H = \ node/timeoffsets.h \ node/transaction.h \ node/txreconciliation.h \ + node/types.h \ node/utxo_snapshot.h \ node/validation_cache_args.h \ noui.h \ @@ -267,6 +271,7 @@ BITCOIN_CORE_H = \ script/descriptor.h \ script/keyorigin.h \ script/miniscript.h \ + script/parsing.h \ script/sigcache.h \ script/sign.h \ script/signingprovider.h \ @@ -297,11 +302,9 @@ BITCOIN_CORE_H = \ util/chaintype.h \ util/check.h \ util/epochguard.h \ - util/error.h \ util/exception.h \ util/fastrange.h \ util/feefrac.h \ - util/fees.h \ util/fs.h \ util/fs_helpers.h \ util/golombrice.h \ @@ -309,7 +312,6 @@ BITCOIN_CORE_H = \ util/hasher.h \ util/insert.h \ util/macros.h \ - util/message.h \ util/moneystr.h \ util/overflow.h \ util/overloaded.h \ @@ -319,7 +321,7 @@ BITCOIN_CORE_H = \ util/serfloat.h \ util/signalinterrupt.h \ util/sock.h \ - util/spanparsing.h \ + util/strencodings.h \ util/string.h \ util/subprocess.h \ util/syserror.h \ @@ -569,6 +571,8 @@ crypto_libbitcoin_crypto_base_la_SOURCES = \ crypto/chacha20poly1305.h \ crypto/chacha20poly1305.cpp \ crypto/common.h \ + crypto/hex_base.cpp \ + crypto/hex_base.h \ crypto/hkdf_sha256_32.cpp \ crypto/hkdf_sha256_32.h \ crypto/hmac_sha256.cpp \ @@ -591,7 +595,8 @@ crypto_libbitcoin_crypto_base_la_SOURCES = \ crypto/sha512.cpp \ crypto/sha512.h \ crypto/siphash.cpp \ - crypto/siphash.h + crypto/siphash.h \ + support/cleanse.cpp # See explanation for -static in crypto_libbitcoin_crypto_base_la's LDFLAGS and # CXXFLAGS above @@ -661,9 +666,7 @@ libbitcoin_consensus_a_SOURCES = \ span.h \ tinyformat.h \ uint256.cpp \ - uint256.h \ - util/strencodings.cpp \ - util/strencodings.h + uint256.h # # common # @@ -673,6 +676,7 @@ libbitcoin_common_a_SOURCES = \ addresstype.cpp \ base58.cpp \ bech32.cpp \ + chainparamsbase.cpp \ chainparams.cpp \ coins.cpp \ common/args.cpp \ @@ -680,8 +684,10 @@ libbitcoin_common_a_SOURCES = \ common/config.cpp \ common/init.cpp \ common/interfaces.cpp \ + common/messages.cpp \ common/run_command.cpp \ common/settings.cpp \ + common/signmessage.cpp \ common/system.cpp \ common/url.cpp \ compressor.cpp \ @@ -711,6 +717,7 @@ libbitcoin_common_a_SOURCES = \ scheduler.cpp \ script/descriptor.cpp \ script/miniscript.cpp \ + script/parsing.cpp \ script/sign.cpp \ script/signingprovider.cpp \ script/solver.cpp \ @@ -723,13 +730,11 @@ 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 \ logging.cpp \ random.cpp \ randomenv.cpp \ streams.cpp \ - support/cleanse.cpp \ sync.cpp \ util/asmap.cpp \ util/batchpriority.cpp \ @@ -737,16 +742,13 @@ libbitcoin_util_a_SOURCES = \ util/bytevectorhash.cpp \ util/chaintype.cpp \ util/check.cpp \ - util/error.cpp \ util/exception.cpp \ util/feefrac.cpp \ - util/fees.cpp \ util/fs.cpp \ util/fs_helpers.cpp \ util/hasher.cpp \ util/sock.cpp \ util/syserror.cpp \ - util/message.cpp \ util/moneystr.cpp \ util/rbf.cpp \ util/readwritefile.cpp \ @@ -755,7 +757,6 @@ libbitcoin_util_a_SOURCES = \ util/threadinterrupt.cpp \ util/threadnames.cpp \ util/serfloat.cpp \ - util/spanparsing.cpp \ util/strencodings.cpp \ util/string.cpp \ util/time.cpp \ @@ -972,7 +973,6 @@ libbitcoinkernel_la_SOURCES = \ script/solver.cpp \ signet.cpp \ streams.cpp \ - support/cleanse.cpp \ support/lockedpool.cpp \ sync.cpp \ txdb.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index c41faa117d6..fa7cadb726a 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -375,6 +375,7 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/script_format.cpp \ test/fuzz/script_interpreter.cpp \ test/fuzz/script_ops.cpp \ + test/fuzz/script_parsing.cpp \ test/fuzz/script_sigcache.cpp \ test/fuzz/script_sign.cpp \ test/fuzz/scriptnum_ops.cpp \ @@ -384,7 +385,6 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/signet.cpp \ test/fuzz/socks5.cpp \ test/fuzz/span.cpp \ - test/fuzz/spanparsing.cpp \ test/fuzz/string.cpp \ test/fuzz/strprintf.cpp \ test/fuzz/system.cpp \ diff --git a/src/base58.cpp b/src/base58.cpp index cf5d62f164f..f9165ed55f7 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -14,6 +14,8 @@ #include +using util::ContainsNoNUL; + /** All alphanumeric characters except for "0", "I", "O", and "l" */ static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; static const int8_t mapBase58[256] = { diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index a13a693ad77..733f8085ca7 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -18,6 +18,7 @@ #include using namespace std::chrono_literals; +using util::Join; const std::function G_TEST_LOG_FUN{}; diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index 8c421c3fec6..a1b880e40b0 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -16,6 +16,8 @@ #include #include +using util::SplitString; + static const char* DEFAULT_BENCH_FILTER = ".*"; static constexpr int64_t DEFAULT_MIN_TIME_MS{10}; /** Priority level default value, run "all" priority levels */ diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index a178abbc93b..44fc2731639 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -42,6 +42,9 @@ #include #include +using util::Join; +using util::ToString; + // The server returns time values from a mockable system clock, but it is not // trivial to get the mocked time from the server, nor is it needed for now, so // just use a plain system_clock. diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 97096dfe3cc..89faa0123a5 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -32,6 +32,11 @@ #include #include +using util::SplitString; +using util::ToString; +using util::TrimString; +using util::TrimStringView; + static bool fCreateBlank; static std::map registers; static const int CONTINUE_EXECUTION=-1; diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index 87af3474738..b6f5c3f15d5 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -24,6 +24,8 @@ #include #include +using util::Join; + const std::function G_TRANSLATION_FUN = nullptr; static void SetupWalletToolArgs(ArgsManager& argsman) diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp index e045b88513e..5e6702ccc3c 100644 --- a/src/blockfilter.cpp +++ b/src/blockfilter.cpp @@ -16,6 +16,8 @@ #include #include +using util::Join; + static const std::map g_filter_types = { {BlockFilterType::BASIC, "basic"}, }; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 539578085b5..5d4401b719c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -21,6 +21,8 @@ #include #include +using util::SplitString; + void ReadSigNetArgs(const ArgsManager& args, CChainParams::SigNetOptions& options) { if (args.IsArgSet("-signetseednode")) { diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 6b9727a158b..e52703c8bf1 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -13,6 +13,8 @@ #include #include +using util::Join; + /** * Name of client reported in the 'version' message. Report the same name * for both bitcoind and bitcoin-qt, to make it harder for attackers to diff --git a/src/common/config.cpp b/src/common/config.cpp index 1c85273f69c..98223fc3e3a 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -27,6 +27,9 @@ #include #include +using util::TrimString; +using util::TrimStringView; + static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector>& options, std::list& sections) { std::string str, prefix; diff --git a/src/common/messages.cpp b/src/common/messages.cpp new file mode 100644 index 00000000000..9e88ca8b0f9 --- /dev/null +++ b/src/common/messages.cpp @@ -0,0 +1,139 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using node::TransactionError; +using util::Join; + +namespace common { +std::string StringForFeeReason(FeeReason reason) +{ + static const std::map fee_reason_strings = { + {FeeReason::NONE, "None"}, + {FeeReason::HALF_ESTIMATE, "Half Target 60% Threshold"}, + {FeeReason::FULL_ESTIMATE, "Target 85% Threshold"}, + {FeeReason::DOUBLE_ESTIMATE, "Double Target 95% Threshold"}, + {FeeReason::CONSERVATIVE, "Conservative Double Target longer horizon"}, + {FeeReason::MEMPOOL_MIN, "Mempool Min Fee"}, + {FeeReason::PAYTXFEE, "PayTxFee set"}, + {FeeReason::FALLBACK, "Fallback fee"}, + {FeeReason::REQUIRED, "Minimum Required Fee"}, + }; + auto reason_string = fee_reason_strings.find(reason); + + if (reason_string == fee_reason_strings.end()) return "Unknown"; + + return reason_string->second; +} + +const std::vector>& FeeModeMap() +{ + static const std::vector> FEE_MODES = { + {"unset", FeeEstimateMode::UNSET}, + {"economical", FeeEstimateMode::ECONOMICAL}, + {"conservative", FeeEstimateMode::CONSERVATIVE}, + }; + return FEE_MODES; +} + +std::string FeeModes(const std::string& delimiter) +{ + return Join(FeeModeMap(), delimiter, [&](const std::pair& i) { return i.first; }); +} + +std::string InvalidEstimateModeErrorMessage() +{ + return "Invalid estimate_mode parameter, must be one of: \"" + FeeModes("\", \"") + "\""; +} + +bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode) +{ + auto searchkey = ToUpper(mode_string); + for (const auto& pair : FeeModeMap()) { + if (ToUpper(pair.first) == searchkey) { + fee_estimate_mode = pair.second; + return true; + } + } + return false; +} + +bilingual_str PSBTErrorString(PSBTError err) +{ + switch (err) { + case PSBTError::MISSING_INPUTS: + return Untranslated("Inputs missing or spent"); + case PSBTError::SIGHASH_MISMATCH: + return Untranslated("Specified sighash value does not match value stored in PSBT"); + case PSBTError::EXTERNAL_SIGNER_NOT_FOUND: + return Untranslated("External signer not found"); + case PSBTError::EXTERNAL_SIGNER_FAILED: + return Untranslated("External signer failed to sign"); + case PSBTError::UNSUPPORTED: + return Untranslated("Signer does not support PSBT"); + // no default case, so the compiler can warn about missing cases + } + assert(false); +} + +bilingual_str TransactionErrorString(const TransactionError err) +{ + switch (err) { + case TransactionError::OK: + return Untranslated("No error"); + case TransactionError::MISSING_INPUTS: + return Untranslated("Inputs missing or spent"); + case TransactionError::ALREADY_IN_CHAIN: + return Untranslated("Transaction already in block chain"); + case TransactionError::MEMPOOL_REJECTED: + return Untranslated("Transaction rejected by mempool"); + case TransactionError::MEMPOOL_ERROR: + return Untranslated("Mempool internal error"); + case TransactionError::MAX_FEE_EXCEEDED: + return Untranslated("Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)"); + case TransactionError::MAX_BURN_EXCEEDED: + return Untranslated("Unspendable output exceeds maximum configured by user (maxburnamount)"); + case TransactionError::INVALID_PACKAGE: + return Untranslated("Transaction rejected due to invalid package"); + // no default case, so the compiler can warn about missing cases + } + assert(false); +} + +bilingual_str ResolveErrMsg(const std::string& optname, const std::string& strBind) +{ + return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind); +} + +bilingual_str InvalidPortErrMsg(const std::string& optname, const std::string& invalid_value) +{ + return strprintf(_("Invalid port specified in %s: '%s'"), optname, invalid_value); +} + +bilingual_str AmountHighWarn(const std::string& optname) +{ + return strprintf(_("%s is set very high!"), optname); +} + +bilingual_str AmountErrMsg(const std::string& optname, const std::string& strValue) +{ + return strprintf(_("Invalid amount for -%s=: '%s'"), optname, strValue); +} +} // namespace common diff --git a/src/common/messages.h b/src/common/messages.h new file mode 100644 index 00000000000..68e7bb21696 --- /dev/null +++ b/src/common/messages.h @@ -0,0 +1,38 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +//! @file common/messages.h is a home for simple string functions returning +//! descriptive messages that are used in RPC and GUI interfaces or log +//! messages, and are called in different parts of the codebase across +//! node/wallet/gui boundaries. + +#ifndef BITCOIN_COMMON_MESSAGES_H +#define BITCOIN_COMMON_MESSAGES_H + +#include + +struct bilingual_str; + +enum class FeeEstimateMode; +enum class FeeReason; +namespace node { +enum class TransactionError; +} // namespace node + +namespace common { +enum class PSBTError; +bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode); +std::string StringForFeeReason(FeeReason reason); +std::string FeeModes(const std::string& delimiter); +std::string InvalidEstimateModeErrorMessage(); +bilingual_str PSBTErrorString(PSBTError error); +bilingual_str TransactionErrorString(const node::TransactionError error); +bilingual_str ResolveErrMsg(const std::string& optname, const std::string& strBind); +bilingual_str InvalidPortErrMsg(const std::string& optname, const std::string& strPort); +bilingual_str AmountHighWarn(const std::string& optname); +bilingual_str AmountErrMsg(const std::string& optname, const std::string& strValue); +} // namespace common + +#endif // BITCOIN_COMMON_MESSAGES_H diff --git a/src/util/message.cpp b/src/common/signmessage.cpp similarity index 98% rename from src/util/message.cpp rename to src/common/signmessage.cpp index 1afb28cc10d..1612751e44d 100644 --- a/src/util/message.cpp +++ b/src/common/signmessage.cpp @@ -3,12 +3,12 @@ // 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 #include #include diff --git a/src/util/message.h b/src/common/signmessage.h similarity index 95% rename from src/util/message.h rename to src/common/signmessage.h index d0e2422574b..215b563bbb2 100644 --- a/src/util/message.h +++ b/src/common/signmessage.h @@ -3,8 +3,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_UTIL_MESSAGE_H -#define BITCOIN_UTIL_MESSAGE_H +#ifndef BITCOIN_COMMON_SIGNMESSAGE_H +#define BITCOIN_COMMON_SIGNMESSAGE_H #include @@ -74,4 +74,4 @@ uint256 MessageHash(const std::string& message); std::string SigningResultString(const SigningResult res); -#endif // BITCOIN_UTIL_MESSAGE_H +#endif // BITCOIN_COMMON_SIGNMESSAGE_H diff --git a/src/common/system.cpp b/src/common/system.cpp index ddd0feda3b8..6d04c8a7bc3 100644 --- a/src/common/system.cpp +++ b/src/common/system.cpp @@ -28,6 +28,8 @@ #include #include +using util::ReplaceAll; + // Application startup time (used for uptime calculation) const int64_t nStartupTime = GetTime(); diff --git a/src/common/types.h b/src/common/types.h new file mode 100644 index 00000000000..0d9cb67ce94 --- /dev/null +++ b/src/common/types.h @@ -0,0 +1,26 @@ +// Copyright (c) 2010-2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +//! @file common/types.h is a home for simple enum and struct type definitions +//! that can be used internally by functions in the libbitcoin_common library, +//! but also used externally by node, wallet, and GUI code. +//! +//! This file is intended to define only simple types that do not have external +//! dependencies. More complicated types should be defined in dedicated header +//! files. + +#ifndef BITCOIN_COMMON_TYPES_H +#define BITCOIN_COMMON_TYPES_H + +namespace common { +enum class PSBTError { + MISSING_INPUTS, + SIGHASH_MISMATCH, + EXTERNAL_SIGNER_NOT_FOUND, + EXTERNAL_SIGNER_FAILED, + UNSUPPORTED, +}; +} // namespace common + +#endif // BITCOIN_COMMON_TYPES_H diff --git a/src/core_read.cpp b/src/core_read.cpp index 5956d9df5fa..114f92fc458 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -16,6 +16,8 @@ #include #include +using util::SplitString; + namespace { class OpCodeParser { diff --git a/src/crypto/hex_base.cpp b/src/crypto/hex_base.cpp new file mode 100644 index 00000000000..67d691b63e1 --- /dev/null +++ b/src/crypto/hex_base.cpp @@ -0,0 +1,67 @@ +// Copyright (c) 2009-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include + +namespace { + +using ByteAsHex = std::array; + +constexpr std::array CreateByteToHexMap() +{ + constexpr char hexmap[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + std::array byte_to_hex{}; + for (size_t i = 0; i < byte_to_hex.size(); ++i) { + byte_to_hex[i][0] = hexmap[i >> 4]; + byte_to_hex[i][1] = hexmap[i & 15]; + } + return byte_to_hex; +} + +} // namespace + +std::string HexStr(const Span s) +{ + std::string rv(s.size() * 2, '\0'); + static constexpr auto byte_to_hex = CreateByteToHexMap(); + static_assert(sizeof(byte_to_hex) == 512); + + char* it = rv.data(); + for (uint8_t v : s) { + std::memcpy(it, byte_to_hex[v].data(), 2); + it += 2; + } + + assert(it == rv.data() + rv.size()); + return rv; +} + +const signed char p_util_hexdigit[256] = +{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; + +signed char HexDigit(char c) +{ + return p_util_hexdigit[(unsigned char)c]; +} + diff --git a/src/crypto/hex_base.h b/src/crypto/hex_base.h new file mode 100644 index 00000000000..cdfea68c29c --- /dev/null +++ b/src/crypto/hex_base.h @@ -0,0 +1,23 @@ +// Copyright (c) 2009-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CRYPTO_HEX_BASE_H +#define BITCOIN_CRYPTO_HEX_BASE_H + +#include + +#include +#include +#include + +/** + * Convert a span of bytes to a lower-case hexadecimal string. + */ +std::string HexStr(const Span s); +inline std::string HexStr(const Span s) { return HexStr(MakeUCharSpan(s)); } +inline std::string HexStr(const Span s) { return HexStr(MakeUCharSpan(s)); } + +signed char HexDigit(char c); + +#endif // BITCOIN_CRYPTO_HEX_BASE_H diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 3eb34dbe6ab..128597157d6 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -23,6 +23,9 @@ #include #include +using util::SplitString; +using util::TrimStringView; + /** WWW-Authenticate to present with 401 Unauthorized response */ static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\""; diff --git a/src/i2p.cpp b/src/i2p.cpp index 962adb124d0..a907cfeacb6 100644 --- a/src/i2p.cpp +++ b/src/i2p.cpp @@ -12,12 +12,12 @@ #include #include #include +#include